/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <sfx2/app.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/event.hxx>
#include <sfx2/navigat.hxx>
#include <svl/stritem.hxx>
#include <unotools/charclass.hxx>
#include <viewdata.hxx>
#include <tabvwsh.hxx>
#include <docsh.hxx>
#include <document.hxx>
#include <rangeutl.hxx>
#include <sc.hrc>
#include <strings.hrc>
#include <bitmaps.hlst>
#include <scresid.hxx>
#include <scmod.hxx>
#include <navicfg.hxx>
#include <navcitem.hxx>
#include <navipi.hxx>
#include <navsett.hxx>
#include <markdata.hxx>
#include <com/sun/star/uno/Reference.hxx>
using namespace com::sun::star;
// maximum values for UI
static SCCOL SCNAV_MAXCOL(const ScSheetLimits& rLimits) { return rLimits.GetMaxColCount(); }
static sal_Int32 SCNAV_COLDIGITS(const ScSheetLimits& rLimits)
{
return static_cast<sal_Int32>( floor( log10( static_cast<double>(SCNAV_MAXCOL(rLimits)))) ) + 1; // 1...256...18278
}
static sal_Int32 SCNAV_COLLETTERS(const ScSheetLimits& rLimits)
{
return ::ScColToAlpha(SCNAV_MAXCOL(rLimits)).getLength(); // A...IV...ZZZ
}
static SCROW SCNAV_MAXROW(const ScSheetLimits& rSheetLimits)
{
return rSheetLimits.GetMaxRowCount();
}
void ScNavigatorDlg::ReleaseFocus()
{
SfxViewShell* pCurSh = SfxViewShell::Current();
if ( pCurSh )
{
vcl::Window* pShellWnd = pCurSh->GetWindow();
if ( pShellWnd )
pShellWnd->GrabFocus();
}
}
namespace
{
SCCOL NumToAlpha(const ScSheetLimits& rSheetLimits, SCCOL nColNo, OUString& rStr)
{
if ( nColNo > SCNAV_MAXCOL(rSheetLimits) )
nColNo = SCNAV_MAXCOL(rSheetLimits);
else if ( nColNo < 1 )
nColNo = 1;
::ScColToAlpha( rStr, nColNo - 1);
return nColNo;
}
SCCOL AlphaToNum(const ScDocument& rDoc, OUString& rStr)
{
SCCOL nColumn = 0;
if ( CharClass::isAsciiAlpha( rStr) )
{
rStr = rStr.toAsciiUpperCase();
if (::AlphaToCol( rDoc, nColumn, rStr))
++nColumn;
if ( (rStr.getLength() > SCNAV_COLLETTERS(rDoc.GetSheetLimits())) ||
(nColumn > SCNAV_MAXCOL(rDoc.GetSheetLimits())) )
{
nColumn = SCNAV_MAXCOL(rDoc.GetSheetLimits());
NumToAlpha( rDoc.GetSheetLimits(), nColumn, rStr );
}
}
else
rStr.clear();
return nColumn;
}
SCCOL NumStrToAlpha(const ScSheetLimits& rSheetLimits, OUString& rStr)
{
SCCOL nColumn = 0;
if ( CharClass::isAsciiNumeric(rStr) )
nColumn = NumToAlpha( rSheetLimits, static_cast<SCCOL>(rStr.toInt32()), rStr );
else
rStr.clear();
return nColumn;
}
}
IMPL_LINK(ScNavigatorDlg, ParseRowInputHdl, int*, result, bool)
{
SCCOL nCol(0);
OUString aStrCol = m_xEdCol->get_text();
if (!aStrCol.isEmpty())
{
if (ScViewData* pData = GetViewData())
{
ScDocument& rDoc = pData->GetDocument();
if ( CharClass::isAsciiNumeric(aStrCol) )
nCol = NumStrToAlpha( rDoc.GetSheetLimits(), aStrCol );
else
nCol = AlphaToNum( rDoc, aStrCol );
}
}
*result = nCol;
return true;
}
IMPL_LINK_NOARG(ScNavigatorDlg, ExecuteColHdl, weld::Entry&, bool)
{
ReleaseFocus();
SCROW nRow = m_xEdRow->get_value();
SCCOL nCol = m_xEdCol->get_value();
if ( (nCol > 0) && (nRow > 0) )
SetCurrentCell(nCol - 1, nRow - 1);
return true;
}
IMPL_LINK_NOARG(ScNavigatorDlg, FormatRowOutputHdl, weld::SpinButton&, void)
{
OUString aStr;
::ScColToAlpha(aStr, m_xEdCol->get_value() - 1);
m_xEdCol->set_text(aStr);
}
IMPL_LINK_NOARG(ScNavigatorDlg, ExecuteRowHdl, weld::Entry&, bool)
{
ReleaseFocus();
SCCOL nCol = m_xEdCol->get_value();
SCROW nRow = m_xEdRow->get_value();
if ( (nCol > 0) && (nRow > 0) )
SetCurrentCell(nCol - 1, nRow - 1);
return true;
}
IMPL_LINK(ScNavigatorDlg, DocumentSelectHdl, weld::ComboBox&, rListBox, void)
{
ScNavigatorDlg::ReleaseFocus();
OUString aDocName = rListBox.get_active_text();
m_xLbEntries->SelectDoc(aDocName);
}
IMPL_LINK(ScNavigatorDlg, ToolBoxSelectHdl, const OUString&, rSelId, void)
{
// Switch the mode?
if (rSelId == "contents" || rSelId == "scenarios")
{
NavListMode eOldMode = eListMode;
NavListMode eNewMode;
if (rSelId == "scenarios")
{
if (eOldMode == NAV_LMODE_SCENARIOS)
eNewMode = NAV_LMODE_AREAS;
else
eNewMode = NAV_LMODE_SCENARIOS;
}
else // on/off
{
if (eOldMode == NAV_LMODE_NONE)
eNewMode = NAV_LMODE_AREAS;
else
eNewMode = NAV_LMODE_NONE;
}
SetListMode(eNewMode);
UpdateButtons();
}
else if (rSelId == "dragmode")
m_xTbxCmd2->set_menu_item_active(u"dragmode"_ustr, !m_xTbxCmd2->get_menu_item_active(u"dragmode"_ustr));
else
{
if (rSelId == "datarange")
MarkDataArea();
else if (rSelId == "start")
StartOfDataArea();
else if (rSelId == "end")
EndOfDataArea();
else if (rSelId == "toggle")
{
m_xLbEntries->ToggleRoot();
UpdateButtons();
}
}
}
IMPL_LINK(ScNavigatorDlg, ToolBoxDropdownClickHdl, const OUString&, rCommand, void)
{
if (!m_xTbxCmd2->get_menu_item_active(rCommand))
return;
// the popup menu of the drop mode has to be called in the
// click (button down) and not in the select (button up)
if (rCommand != "dragmode")
return;
switch (GetDropMode())
{
case 0:
m_xDragModeMenu->set_active(u"hyperlink"_ustr, true);
break;
case 1:
m_xDragModeMenu->set_active(u"link"_ustr, true);
break;
case 2:
m_xDragModeMenu->set_active(u"copy"_ustr, true);
break;
}
}
IMPL_LINK(ScNavigatorDlg, MenuSelectHdl, const OUString&, rIdent, void)
{
if (rIdent == u"hyperlink")
SetDropMode(0);
else if (rIdent == u"link")
SetDropMode(1);
else if (rIdent == u"copy")
SetDropMode(2);
}
void ScNavigatorDlg::UpdateButtons()
{
NavListMode eMode = eListMode;
m_xTbxCmd2->set_item_active(u"scenarios"_ustr, eMode == NAV_LMODE_SCENARIOS);
m_xTbxCmd1->set_item_active(u"contents"_ustr, eMode != NAV_LMODE_NONE);
// the toggle button:
if (eMode == NAV_LMODE_SCENARIOS || eMode == NAV_LMODE_NONE)
{
m_xTbxCmd2->set_item_sensitive(u"toggle"_ustr, false);
m_xTbxCmd2->set_item_active(u"toggle"_ustr, false);
}
else
{
m_xTbxCmd2->set_item_sensitive(u"toggle"_ustr, true);
bool bRootSet = m_xLbEntries->GetRootType() != ScContentId::ROOT;
m_xTbxCmd2->set_item_active(u"toggle"_ustr, bRootSet);
}
OUString sImageId;
switch (nDropMode)
{
case SC_DROPMODE_URL:
sImageId = RID_BMP_DROP_URL;
break;
case SC_DROPMODE_LINK:
sImageId = RID_BMP_DROP_LINK;
break;
case SC_DROPMODE_COPY:
sImageId = RID_BMP_DROP_COPY;
break;
}
m_xTbxCmd2->set_item_icon_name(u"dragmode"_ustr, sImageId);
}
ScNavigatorSettings::ScNavigatorSettings()
: mnRootSelected(ScContentId::ROOT)
, mnChildSelected(SC_CONTENT_NOCHILD)
{
maExpandedVec.fill(false);
}
class ScNavigatorWin : public SfxNavigator
{
private:
std::unique_ptr<ScNavigatorDlg> m_xNavigator;
public:
ScNavigatorWin(SfxBindings* _pBindings, SfxChildWindow* pMgr,
vcl::Window* pParent, SfxChildWinInfo* pInfo);
virtual void StateChanged(StateChangedType nStateChange) override;
virtual void dispose() override
{
m_xNavigator.reset();
SfxNavigator::dispose();
}
virtual ~ScNavigatorWin() override
{
disposeOnce();
}
};
ScNavigatorWin::ScNavigatorWin(SfxBindings* _pBindings, SfxChildWindow* _pMgr,
vcl::Window* _pParent, SfxChildWinInfo* pInfo)
: SfxNavigator(_pBindings, _pMgr, _pParent, pInfo)
{
m_xNavigator = std::make_unique<ScNavigatorDlg>(_pBindings, m_xContainer.get(), this);
SetMinOutputSizePixel(GetOptimalSize());
}
ScNavigatorDlg::ScNavigatorDlg(SfxBindings* pB, weld::Widget* pParent, SfxNavigator* pNavigatorDlg)
: PanelLayout(pParent, u"NavigatorPanel"_ustr, u"modules/scalc/ui/navigatorpanel.ui"_ustr)
, rBindings(*pB)
, m_xEdCol(m_xBuilder->weld_spin_button(u"column"_ustr))
, m_xEdRow(m_xBuilder->weld_spin_button(u"row"_ustr))
, m_xTbxCmd1(m_xBuilder->weld_toolbar(u"toolbox1"_ustr))
, m_xTbxCmd2(m_xBuilder->weld_toolbar(u"toolbox2"_ustr))
, m_xLbEntries(new ScContentTree(m_xBuilder->weld_tree_view(u"contentbox"_ustr), this))
, m_xScenarioBox(m_xBuilder->weld_widget(u"scenariobox"_ustr))
, m_xWndScenarios(new ScScenarioWindow(*m_xBuilder,
ScResId(SCSTR_QHLP_SCEN_LISTBOX), ScResId(SCSTR_QHLP_SCEN_COMMENT)))
, m_xLbDocuments(m_xBuilder->weld_combo_box(u"documents"_ustr))
, m_xDragModeMenu(m_xBuilder->weld_menu(u"dragmodemenu"_ustr))
, m_xNavigatorDlg(pNavigatorDlg)
, aContentIdle("ScNavigatorDlg aContentIdle")
, aStrActiveWin(ScResId(SCSTR_ACTIVEWIN))
, pViewData(nullptr )
, eListMode(NAV_LMODE_NONE)
, nDropMode(SC_DROPMODE_URL)
, nCurCol(0)
, nCurRow(0)
, nCurTab(0)
{
UpdateInitShow();
UpdateSheetLimits();
m_xEdRow->set_width_chars(5);
//max rows is 1,000,000, which is too long for typical use
m_xEdRow->connect_activate(LINK(this, ScNavigatorDlg, ExecuteRowHdl));
m_xEdCol->connect_activate(LINK(this, ScNavigatorDlg, ExecuteColHdl));
m_xEdCol->connect_output(LINK(this, ScNavigatorDlg, FormatRowOutputHdl));
m_xEdCol->connect_input(LINK(this, ScNavigatorDlg, ParseRowInputHdl));
m_xTbxCmd1->connect_clicked(LINK(this, ScNavigatorDlg, ToolBoxSelectHdl));
m_xTbxCmd2->connect_clicked(LINK(this, ScNavigatorDlg, ToolBoxSelectHdl));
m_xTbxCmd2->set_item_menu(u"dragmode"_ustr, m_xDragModeMenu.get());
m_xDragModeMenu->connect_activate(LINK(this, ScNavigatorDlg, MenuSelectHdl));
m_xTbxCmd2->connect_menu_toggled(LINK(this, ScNavigatorDlg, ToolBoxDropdownClickHdl));
ScNavipiCfg& rCfg = SC_MOD()->GetNavipiCfg();
nDropMode = rCfg.GetDragMode();
m_xLbDocuments->set_size_request(42, -1); // set a nominal width so it takes width of surroundings
m_xLbDocuments->connect_changed(LINK(this, ScNavigatorDlg, DocumentSelectHdl));
aStrActive = " (" + ScResId(SCSTR_ACTIVE) + ")"; // " (active)"
aStrNotActive = " (" + ScResId(SCSTR_NOTACTIVE) + ")"; // " (not active)"
rBindings.ENTERREGISTRATIONS();
mvBoundItems[0].reset(new ScNavigatorControllerItem(SID_CURRENTCELL,*this,rBindings));
mvBoundItems[1].reset(new ScNavigatorControllerItem(SID_CURRENTTAB,*this,rBindings));
mvBoundItems[2].reset(new ScNavigatorControllerItem(SID_CURRENTDOC,*this,rBindings));
mvBoundItems[3].reset(new ScNavigatorControllerItem(SID_SELECT_SCENARIO,*this,rBindings));
rBindings.LEAVEREGISTRATIONS();
StartListening( *(SfxGetpApp()) );
StartListening( rBindings );
// was a category chosen as root?
ScContentId nLastRoot = rCfg.GetRootType();
if ( nLastRoot != ScContentId::ROOT )
m_xLbEntries->SetRootType( nLastRoot );
GetDocNames(nullptr);
UpdateButtons();
UpdateColumn();
UpdateRow();
UpdateTable(nullptr);
m_xLbEntries->hide();
m_xScenarioBox->hide();
aContentIdle.SetInvokeHandler( LINK( this, ScNavigatorDlg, TimeHdl ) );
aContentIdle.SetPriority( TaskPriority::LOWEST );
m_xLbEntries->SetNavigatorDlgFlag(true);
// if scenario was active, switch on
NavListMode eNavMode = static_cast<NavListMode>(rCfg.GetListMode());
if (eNavMode == NAV_LMODE_SCENARIOS)
m_xTbxCmd2->set_item_active(u"scenarios"_ustr, true);
else
eNavMode = NAV_LMODE_AREAS;
SetListMode(eNavMode);
if(comphelper::LibreOfficeKit::isActive())
{
m_xBuilder->weld_container(u"gridbuttons"_ustr)->hide();
m_xLbDocuments->hide();
}
}
weld::Window* ScNavigatorDlg::GetFrameWeld() const
{
if (m_xNavigatorDlg)
return m_xNavigatorDlg->GetFrameWeld();
return PanelLayout::GetFrameWeld();
}
void ScNavigatorDlg::UpdateSheetLimits()
{
if (ScViewData* pData = GetViewData())
{
ScDocument& rDoc = pData->GetDocument();
m_xEdRow->set_range(1, SCNAV_MAXROW(rDoc.GetSheetLimits()));
m_xEdCol->set_range(1, SCNAV_MAXCOL(rDoc.GetSheetLimits()));
m_xEdCol->set_width_chars(SCNAV_COLDIGITS(rDoc.GetSheetLimits())); // 1...256...18278 or A...IV...ZZZ
}
}
void ScNavigatorDlg::UpdateInitShow()
{
// When the navigator is displayed in the sidebar, or is otherwise
// docked, it has the whole deck to fill. Therefore hide the button that
// hides all controls below the top two rows of buttons.
m_xTbxCmd1->set_item_visible(u"contents"_ustr, ParentIsFloatingWindow(m_xNavigatorDlg));
}
void ScNavigatorWin::StateChanged(StateChangedType nStateChange)
{
SfxNavigator::StateChanged(nStateChange);
if (nStateChange == StateChangedType::InitShow)
m_xNavigator->UpdateInitShow();
}
ScNavigatorDlg::~ScNavigatorDlg()
{
aContentIdle.Stop();
for (auto & p : mvBoundItems)
p.reset();
moMarkArea.reset();
EndListening( *(SfxGetpApp()) );
EndListening( rBindings );
m_xEdCol.reset();
m_xEdRow.reset();
m_xTbxCmd1.reset();
m_xTbxCmd2.reset();
m_xDragModeMenu.reset();
m_xLbEntries.reset();
m_xWndScenarios.reset();
m_xScenarioBox.reset();
m_xLbDocuments.reset();
}
void ScNavigatorDlg::Notify( SfxBroadcaster&, const SfxHint& rHint )
{
if (rHint.GetId() == SfxHintId::ThisIsAnSfxEventHint)
{
// This is for when the document might change and the navigator
// wants to update for the new document, which isn't a scenario
// that happens in online.
if (comphelper::LibreOfficeKit::isActive())
return;
const SfxEventHint& rEventHint = static_cast<const SfxEventHint&>(rHint);
if (rEventHint.GetEventId() == SfxEventHintId::ActivateDoc)
{
UpdateSheetLimits();
bool bRefreshed = m_xLbEntries->ActiveDocChanged();
// UpdateAll just possibly calls Refresh (and always
// ContentUpdated) so if ActiveDocChanged already called Refresh
// skip re-calling it
if (bRefreshed)
ContentUpdated();
else
UpdateAll();
}
}
else
{
const SfxHintId nHintId = rHint.GetId();
if (nHintId == SfxHintId::ScDocNameChanged)
{
m_xLbEntries->ActiveDocChanged();
}
else if (NAV_LMODE_NONE == eListMode)
{
// Table not any more
}
else
{
switch ( nHintId )
{
case SfxHintId::ScTablesChanged:
m_xLbEntries->Refresh( ScContentId::TABLE );
break;
case SfxHintId::ScDbAreasChanged:
m_xLbEntries->Refresh( ScContentId::DBAREA );
break;
case SfxHintId::ScAreasChanged:
m_xLbEntries->Refresh( ScContentId::RANGENAME );
break;
case SfxHintId::ScDrawChanged:
m_xLbEntries->Refresh( ScContentId::GRAPHIC );
m_xLbEntries->Refresh( ScContentId::OLEOBJECT );
m_xLbEntries->Refresh( ScContentId::DRAWING );
aContentIdle.Start(); // Do not search notes immediately
break;
case SfxHintId::ScAreaLinksChanged:
m_xLbEntries->Refresh( ScContentId::AREALINK );
break;
// SfxHintId::DocChanged not only at document change
case SfxHintId::ScNavigatorUpdateAll:
UpdateAll();
break;
case SfxHintId::ScDataChanged:
case SfxHintId::ScAnyDataChanged:
aContentIdle.Start(); // Do not search notes immediately
break;
case SfxHintId::ScSelectionChanged:
UpdateSelection();
break;
default:
break;
}
}
}
}
IMPL_LINK( ScNavigatorDlg, TimeHdl, Timer*, pIdle, void )
{
if ( pIdle != &aContentIdle )
return;
m_xLbEntries->Refresh( ScContentId::NOTE );
}
void ScNavigatorDlg::SetDropMode(sal_uInt16 nNew)
{
nDropMode = nNew;
UpdateButtons();
ScNavipiCfg& rCfg = SC_MOD()->GetNavipiCfg();
rCfg.SetDragMode(nDropMode);
}
void ScNavigatorDlg::SetCurrentCell( SCCOL nColNo, SCROW nRowNo )
{
if ((nColNo+1 == nCurCol) && (nRowNo+1 == nCurRow))
return;
// SID_CURRENTCELL == Item #0 clear cache, so it's possible
// setting the current cell even in combined areas
mvBoundItems[0]->ClearCache();
ScAddress aScAddress( nColNo, nRowNo, 0 );
OUString aAddr(aScAddress.Format(ScRefFlags::ADDR_ABS));
bool bUnmark = false;
if ( GetViewData() )
bUnmark = !pViewData->GetMarkData().IsCellMarked( nColNo, nRowNo );
SfxStringItem aPosItem( SID_CURRENTCELL, aAddr );
SfxBoolItem aUnmarkItem( FN_PARAM_1, bUnmark ); // cancel selection
rBindings.GetDispatcher()->ExecuteList(SID_CURRENTCELL,
SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
{ &aPosItem, &aUnmarkItem });
}
void ScNavigatorDlg::SetCurrentCellStr( const OUString& rName )
{
mvBoundItems[0]->ClearCache();
SfxStringItem aNameItem( SID_CURRENTCELL, rName );
rBindings.GetDispatcher()->ExecuteList(SID_CURRENTCELL,
SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
{ &aNameItem });
}
void ScNavigatorDlg::SetCurrentTable( SCTAB nTabNo )
{
if ( nTabNo != nCurTab )
{
// Table for basic is base-1
SfxUInt16Item aTabItem( SID_CURRENTTAB, static_cast<sal_uInt16>(nTabNo) + 1 );
rBindings.GetDispatcher()->ExecuteList(SID_CURRENTTAB,
SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
{ &aTabItem });
}
}
void ScNavigatorDlg::SetCurrentTableStr( std::u16string_view rName )
{
if (!GetViewData()) return;
ScDocument& rDoc = pViewData->GetDocument();
SCTAB nCount = rDoc.GetTableCount();
OUString aTabName;
SCTAB nLastSheet = 0;
for (SCTAB i = 0; i<nCount; i++)
{
rDoc.GetName(i, aTabName);
if (aTabName == rName)
{
// Check if this is a Scenario sheet and if so select the sheet
// where it belongs to, which is the previous non-Scenario sheet.
if (rDoc.IsScenario(i))
{
SetCurrentTable(nLastSheet);
return;
}
else
{
SetCurrentTable(i);
return;
}
}
else
{
if (!rDoc.IsScenario(i))
nLastSheet = i;
}
}
}
void ScNavigatorDlg::SetCurrentObject( const OUString& rName )
{
SfxStringItem aNameItem( SID_CURRENTOBJECT, rName );
rBindings.GetDispatcher()->ExecuteList( SID_CURRENTOBJECT,
SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
{ &aNameItem });
}
void ScNavigatorDlg::SetCurrentDoc( const OUString& rDocName ) // activate
{
SfxStringItem aDocItem( SID_CURRENTDOC, rDocName );
rBindings.GetDispatcher()->ExecuteList( SID_CURRENTDOC,
SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
{ &aDocItem });
}
void ScNavigatorDlg::UpdateSelection()
{
ScTabViewShell* pViewSh = GetTabViewShell();
if( !pViewSh )
return;
uno::Reference< drawing::XShapes > xShapes = pViewSh->getSelectedXShapes();
if( !xShapes )
return;
uno::Reference< container::XIndexAccess > xIndexAccess(
xShapes, uno::UNO_QUERY_THROW );
if( xIndexAccess->getCount() > 1 )
return;
uno::Reference< drawing::XShape > xShape;
if( xIndexAccess->getByIndex(0) >>= xShape )
{
uno::Reference< container::XNamed > xNamed( xShape, uno::UNO_QUERY_THROW );
OUString sName = xNamed->getName();
if (!sName.isEmpty())
{
m_xLbEntries->SelectEntryByName( ScContentId::DRAWING, sName );
}
}
}
ScTabViewShell* ScNavigatorDlg::GetTabViewShell()
{
return dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
}
ScNavigatorSettings* ScNavigatorDlg::GetNavigatorSettings()
{
// Don't store the settings pointer here, because the settings belong to
// the view, and the view may be closed while the navigator is open (reload).
// If the pointer is cached here again later for performance reasons, it has to
// be forgotten when the view is closed.
ScTabViewShell* pViewSh = GetTabViewShell();
return pViewSh ? pViewSh->GetNavigatorSettings() : nullptr;
}
ScViewData* ScNavigatorDlg::GetViewData()
{
ScTabViewShell* pViewSh = GetTabViewShell();
pViewData = pViewSh ? &pViewSh->GetViewData() : nullptr;
return pViewData;
}
void ScNavigatorDlg::UpdateColumn( const SCCOL* pCol )
{
if ( pCol )
nCurCol = *pCol;
else if ( GetViewData() )
nCurCol = pViewData->GetCurX() + 1;
m_xEdCol->set_value(nCurCol);
}
void ScNavigatorDlg::UpdateRow( const SCROW* pRow )
{
if ( pRow )
nCurRow = *pRow;
else if ( GetViewData() )
nCurRow = pViewData->GetCurY() + 1;
m_xEdRow->set_value(nCurRow);
}
void ScNavigatorDlg::UpdateTable( const SCTAB* pTab )
{
if ( pTab )
nCurTab = *pTab;
else if ( GetViewData() )
nCurTab = pViewData->GetTabNo();
}
void ScNavigatorDlg::UpdateAll()
{
switch (eListMode)
{
case NAV_LMODE_AREAS:
m_xLbEntries->Refresh();
break;
case NAV_LMODE_NONE:
//! ???
break;
default:
break;
}
ContentUpdated(); // not again
}
void ScNavigatorDlg::ContentUpdated()
{
aContentIdle.Stop();
}
void ScNavigatorDlg::SetListMode(NavListMode eMode)
{
if (eMode != eListMode)
{
bool bForceParentResize = ParentIsFloatingWindow(m_xNavigatorDlg) &&
(eMode == NAV_LMODE_NONE || eListMode == NAV_LMODE_NONE);
SfxNavigator* pNav = bForceParentResize ? m_xNavigatorDlg.get() : nullptr;
if (pNav && eMode == NAV_LMODE_NONE) //save last normal size on minimizing
aExpandedSize = pNav->GetSizePixel();
eListMode = eMode;
switch (eMode)
{
case NAV_LMODE_NONE:
ShowList(false);
break;
case NAV_LMODE_AREAS:
m_xLbEntries->Refresh();
ShowList(true);
break;
case NAV_LMODE_SCENARIOS:
ShowScenarios();
break;
}
UpdateButtons();
if (eMode != NAV_LMODE_NONE)
{
ScNavipiCfg& rCfg = SC_MOD()->GetNavipiCfg();
rCfg.SetListMode( static_cast<sal_uInt16>(eMode) );
}
if (pNav)
{
pNav->InvalidateChildSizeCache();
Size aOptimalSize(pNav->GetOptimalSize());
Size aNewSize(pNav->GetOutputSizePixel());
aNewSize.setHeight( eMode == NAV_LMODE_NONE ? aOptimalSize.Height() : aExpandedSize.Height() );
pNav->SetMinOutputSizePixel(aOptimalSize);
pNav->SetOutputSizePixel(aNewSize);
}
}
if (moMarkArea)
UnmarkDataArea();
}
void ScNavigatorDlg::ShowList(bool bShow)
{
if (bShow)
{
m_xLbEntries->show();
m_xLbDocuments->show();
}
else
{
m_xLbEntries->hide();
m_xLbDocuments->hide();
}
m_xScenarioBox->hide();
}
void ScNavigatorDlg::ShowScenarios()
{
rBindings.Invalidate( SID_SELECT_SCENARIO );
rBindings.Update( SID_SELECT_SCENARIO );
m_xScenarioBox->show();
m_xLbDocuments->show();
m_xLbEntries->hide();
}
// documents for Dropdown-Listbox
void ScNavigatorDlg::GetDocNames( const OUString* pManualSel )
{
m_xLbDocuments->clear();
m_xLbDocuments->freeze();
ScDocShell* pCurrentSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
OUString aSelEntry;
SfxObjectShell* pSh = SfxObjectShell::GetFirst();
while ( pSh )
{
if ( dynamic_cast<const ScDocShell*>( pSh) != nullptr )
{
OUString aName = pSh->GetTitle();
OUString aEntry = aName;
if (pSh == pCurrentSh)
aEntry += aStrActive;
else
aEntry += aStrNotActive;
m_xLbDocuments->append_text(aEntry);
if ( pManualSel ? ( aName == *pManualSel )
: ( pSh == pCurrentSh ) )
aSelEntry = aEntry; // complete entry for selection
}
pSh = SfxObjectShell::GetNext( *pSh );
}
m_xLbDocuments->append_text(aStrActiveWin);
m_xLbDocuments->thaw();
m_xLbDocuments->set_active_text(aSelEntry);
}
void ScNavigatorDlg::MarkDataArea()
{
ScTabViewShell* pViewSh = GetTabViewShell();
if ( !pViewSh )
return;
if ( !moMarkArea )
moMarkArea.emplace();
pViewSh->MarkDataArea();
const ScRange& aMarkRange = pViewSh->GetViewData().GetMarkData().GetMarkArea();
moMarkArea->nColStart = aMarkRange.aStart.Col();
moMarkArea->nRowStart = aMarkRange.aStart.Row();
moMarkArea->nColEnd = aMarkRange.aEnd.Col();
moMarkArea->nRowEnd = aMarkRange.aEnd.Row();
moMarkArea->nTab = aMarkRange.aStart.Tab();
}
void ScNavigatorDlg::UnmarkDataArea()
{
ScTabViewShell* pViewSh = GetTabViewShell();
if ( pViewSh )
{
pViewSh->Unmark();
moMarkArea.reset();
}
}
void ScNavigatorDlg::StartOfDataArea()
{
// pMarkArea evaluate ???
if ( GetViewData() )
{
ScMarkData& rMark = pViewData->GetMarkData();
const ScRange& aMarkRange = rMark.GetMarkArea();
SCCOL nCol = aMarkRange.aStart.Col();
SCROW nRow = aMarkRange.aStart.Row();
if ( (nCol+1 != m_xEdCol->get_value()) || (nRow+1 != m_xEdRow->get_value()) )
SetCurrentCell( nCol, nRow );
}
}
void ScNavigatorDlg::EndOfDataArea()
{
// pMarkArea evaluate ???
if ( GetViewData() )
{
ScMarkData& rMark = pViewData->GetMarkData();
const ScRange& aMarkRange = rMark.GetMarkArea();
SCCOL nCol = aMarkRange.aEnd.Col();
SCROW nRow = aMarkRange.aEnd.Row();
if ( (nCol+1 != m_xEdCol->get_value()) || (nRow+1 != m_xEdRow->get_value()) )
SetCurrentCell( nCol, nRow );
}
}
SFX_IMPL_DOCKINGWINDOW(ScNavigatorWrapper, SID_NAVIGATOR);
ScNavigatorWrapper::ScNavigatorWrapper(vcl::Window *_pParent, sal_uInt16 nId,
SfxBindings* pBindings, SfxChildWinInfo* pInfo)
: SfxNavigatorWrapper(_pParent, nId)
{
SetWindow(VclPtr<ScNavigatorWin>::Create(pBindings, this, _pParent, pInfo));
Initialize();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V1053 Calling the 'GetOptimalSize' virtual function in the constructor may lead to unexpected result at runtime.