summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoel Power <noel.power@suse.com>2013-08-23 15:56:46 +0100
committerNoel Power <noel.power@suse.com>2013-08-26 14:42:17 +0100
commite5755f4022c1e99514a236a97a9a62552dd8e9fe (patch)
tree296e2d350baef323c686af6a940e0efeb9cb37e9
parent37e36eca17563b2580abf97f4f46a470387e5b70 (diff)
treelist for autofilter ( nested nodes for dates ) ( using SvxTreeListBox )
Attempt at trying to get more interopable behavior, imho the way dates are presented in the autofilter of the "other" well known spreadsheet application is very nice and intuitive. This attempt here is lacking in that a) for some reason I am not getting the node icons ( and subsequently can't sing le click anything to expand the nodes ) Only double clicking works to expand b) the 'check' behaviour is not quite right, e.g. as simple example is if all nodes of a particular date are unset then clicking the leaf node ( e.g. day ) wont set the ancestor nodes. Change-Id: Iaa89cac21fb18074ff64a984f099a35851c2fe3c
-rw-r--r--sc/inc/typedstrdata.hxx5
-rw-r--r--sc/source/core/data/column3.cxx6
-rw-r--r--sc/source/core/tool/typedstrdata.cxx25
-rw-r--r--sc/source/ui/cctrl/checklistmenu.cxx208
-rw-r--r--sc/source/ui/inc/checklistmenu.hxx29
-rw-r--r--sc/source/ui/view/gridwin.cxx5
6 files changed, 261 insertions, 17 deletions
diff --git a/sc/inc/typedstrdata.hxx b/sc/inc/typedstrdata.hxx
index 346978bf8446..7d8cf4483400 100644
--- a/sc/inc/typedstrdata.hxx
+++ b/sc/inc/typedstrdata.hxx
@@ -27,13 +27,15 @@ public:
};
ScTypedStrData( const OUString& rStr, double nVal = 0.0,
- StringType eType = Standard );
+ StringType eType = Standard, bool bDate = false );
ScTypedStrData( const ScTypedStrData& rCpy );
bool IsStrData() const;
+ bool IsDate() const;
SC_DLLPUBLIC const OUString& GetString() const;
StringType GetStringType() const;
+ double GetValue() const { return mfValue; }
struct LessCaseSensitive : std::binary_function<ScTypedStrData, ScTypedStrData, bool>
{
@@ -62,6 +64,7 @@ private:
OUString maStrValue;
double mfValue;
StringType meStrType;
+ bool mbIsDate;
};
class FindTypedStrData : std::unary_function<ScTypedStrData, bool>
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index b452b68b17ed..ce2d81feaccd 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -1795,15 +1795,17 @@ class FilterEntriesHandler
}
short nType = pFormatter->GetType(nFormat);
+ bool bDate = false;
if ((nType & NUMBERFORMAT_DATE) && !(nType & NUMBERFORMAT_TIME))
{
// special case for date values. Disregard the time
// element if the number format is of date type.
fVal = rtl::math::approxFloor(fVal);
mbHasDates = true;
+ bDate = true;
}
-
- mrStrings.push_back(ScTypedStrData(aStr, fVal, ScTypedStrData::Value));
+ // maybe extend ScTypedStrData enum is also an option here
+ mrStrings.push_back(ScTypedStrData(aStr, fVal, ScTypedStrData::Value,bDate));
}
public:
diff --git a/sc/source/core/tool/typedstrdata.cxx b/sc/source/core/tool/typedstrdata.cxx
index 57d73588ac85..2ffd773b9539 100644
--- a/sc/source/core/tool/typedstrdata.cxx
+++ b/sc/source/core/tool/typedstrdata.cxx
@@ -20,6 +20,9 @@ bool ScTypedStrData::LessCaseSensitive::operator() (const ScTypedStrData& left,
if (left.meStrType == Value)
return left.mfValue < right.mfValue;
+ if (left.mbIsDate != right.mbIsDate)
+ return left.mbIsDate < right.mbIsDate;
+
return ScGlobal::GetCaseCollator()->compareString(
left.maStrValue, right.maStrValue) < 0;
}
@@ -32,6 +35,9 @@ bool ScTypedStrData::LessCaseInsensitive::operator() (const ScTypedStrData& left
if (left.meStrType == Value)
return left.mfValue < right.mfValue;
+ if (left.mbIsDate != right.mbIsDate)
+ return left.mbIsDate < right.mbIsDate;
+
return ScGlobal::GetCollator()->compareString(
left.maStrValue, right.maStrValue) < 0;
}
@@ -44,6 +50,9 @@ bool ScTypedStrData::EqualCaseSensitive::operator() (const ScTypedStrData& left,
if (left.meStrType == Value && left.mfValue != right.mfValue)
return false;
+ if (left.mbIsDate != right.mbIsDate )
+ return false;
+
return ScGlobal::GetCaseCollator()->compareString(
left.maStrValue, right.maStrValue) == 0;
}
@@ -56,6 +65,9 @@ bool ScTypedStrData::EqualCaseInsensitive::operator() (const ScTypedStrData& lef
if (left.meStrType == Value && left.mfValue != right.mfValue)
return false;
+ if (left.mbIsDate != right.mbIsDate )
+ return false;
+
return ScGlobal::GetCollator()->compareString(
left.maStrValue, right.maStrValue) == 0;
}
@@ -75,21 +87,28 @@ bool ScTypedStrData::operator< (const ScTypedStrData& r) const
}
ScTypedStrData::ScTypedStrData(
- const OUString& rStr, double nVal, StringType nType ) :
+ const OUString& rStr, double nVal, StringType nType, bool bDate ) :
maStrValue(rStr),
mfValue(nVal),
- meStrType(nType) {}
+ meStrType(nType),
+ mbIsDate( bDate ) {}
ScTypedStrData::ScTypedStrData( const ScTypedStrData& rCpy ) :
maStrValue(rCpy.maStrValue),
mfValue(rCpy.mfValue),
- meStrType(rCpy.meStrType) {}
+ meStrType(rCpy.meStrType),
+ mbIsDate( rCpy.mbIsDate ) {}
bool ScTypedStrData::IsStrData() const
{
return meStrType != Value;
}
+bool ScTypedStrData::IsDate() const
+{
+ return mbIsDate;
+}
+
const OUString& ScTypedStrData::GetString() const
{
return maStrValue;
diff --git a/sc/source/ui/cctrl/checklistmenu.cxx b/sc/source/ui/cctrl/checklistmenu.cxx
index e32c03d75973..08aa1b405bb0 100644
--- a/sc/source/ui/cctrl/checklistmenu.cxx
+++ b/sc/source/ui/cctrl/checklistmenu.cxx
@@ -29,6 +29,8 @@
#include <com/sun/star/accessibility/XAccessible.hpp>
#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include "svtools/fmtfield.hxx"
+#include "document.hxx"
using ::com::sun::star::uno::Reference;
using ::com::sun::star::accessibility::XAccessible;
@@ -850,6 +852,11 @@ void ScMenuFloatingWindow::terminateAllPopupMenus()
mpParentMenu->terminateAllPopupMenus();
}
+ScDocument* ScMenuFloatingWindow::getDoc()
+{
+ return mpDoc;
+}
+
// ============================================================================
ScCheckListMenuWindow::Config::Config() :
@@ -1078,7 +1085,7 @@ void ScCheckListMenuWindow::setAllMemberState(bool bSet)
{
size_t n = maMembers.size();
for (size_t i = 0; i < n; ++i)
- maChecks.CheckEntryPos(static_cast<sal_uInt16>(i), bSet);
+ maChecks.CheckEntryPos( maMembers[i].maName, maMembers[i].mpParent, bSet);
if (!maConfig.mbAllowEmptySet)
// We need to have at least one member selected.
@@ -1088,8 +1095,9 @@ void ScCheckListMenuWindow::setAllMemberState(bool bSet)
void ScCheckListMenuWindow::selectCurrentMemberOnly(bool bSet)
{
setAllMemberState(!bSet);
- sal_uInt16 nSelected = maChecks.GetSelectEntryPos();
- maChecks.CheckEntryPos(nSelected, bSet);
+// sal_uInt16 nSelected = maChecks.GetSelectEntryPos();
+ SvTreeListEntry* pEntry = maChecks.GetCurEntry();
+ maChecks.CheckEntryPos(pEntry, bSet );
}
void ScCheckListMenuWindow::cycleFocus(bool bReverse)
@@ -1160,7 +1168,9 @@ IMPL_LINK( ScCheckListMenuWindow, CheckHdl, SvTreeListBox*, pChecks )
{
if (pChecks != &maChecks)
return 0;
-
+ SvTreeListEntry* pEntry = pChecks->GetHdlEntry();
+ if ( pEntry )
+ maChecks.CheckEntryPos( pEntry, ( pChecks->GetCheckButtonState( pEntry ) == SV_BUTTON_CHECKED ) );
size_t nNumChecked = maChecks.GetCheckedEntryCount();
if (nNumChecked == maMembers.size())
// all members visible
@@ -1267,14 +1277,177 @@ void ScCheckListMenuWindow::setMemberSize(size_t n)
maMembers.reserve(n);
}
+void ScCheckListMenuWindow::addDateMember(const OUString& rsName, double nVal, bool bVisible)
+{
+ ScDocument* pDoc = getDoc();
+ if ( pDoc )
+ {
+ SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
+ OUString rsDate;
+ if ( pFormatter )
+ {
+ OUString sFormat("YYYY/MMMM/DD");
+ Color* pColor = NULL;
+ pFormatter->GetPreviewString(sFormat,
+ nVal,
+ rsDate,
+ &pColor,
+ ScGlobal::eLnge );
+ }
+ maChecks.SetUpdateMode(false);
+ sal_Int32 nIndex = 0;
+ std::vector< OUString > vParts;
+ OUString sParent;
+ SvTreeListEntry* pParent = NULL;
+ int count = 0;
+ do
+ {
+ OUString sPart = rsDate.getToken( 0, '/', nIndex );
+ bool bLeaf = ( ++count == 3 );
+ SvTreeListEntry* pChild = maChecks.FindEntry( pParent, sPart );
+ if ( !pChild )
+ {
+ if ( bLeaf )
+ pChild = maChecks.SvTreeListBox::InsertEntry( sPart, pParent, sal_False, LISTBOX_APPEND, NULL, SvLBoxButtonKind_enabledCheckbox );
+ else
+ pChild = maChecks.SvTreeListBox::InsertEntry( sPart, pParent, sal_True, LISTBOX_APPEND, NULL, SvLBoxButtonKind_enabledCheckbox );
+ Member aMember;
+ aMember.maName = sPart;
+ aMember.maRealName = rsName;
+ aMember.mbDate = true;
+ aMember.mbLeaf = bLeaf;
+ aMember.mbVisible = bVisible;
+ aMember.mpParent = pParent;
+ maMembers.push_back(aMember);
+ }
+ sParent = sPart;
+ pParent = pChild;
+ } while ( nIndex >= 0 );
+ maChecks.SetUpdateMode(true);
+ }
+}
+
void ScCheckListMenuWindow::addMember(const OUString& rName, bool bVisible)
{
Member aMember;
aMember.maName = rName;
+ aMember.mbDate = false;
+ aMember.mbLeaf = true;
aMember.mbVisible = bVisible;
+ aMember.mpParent = NULL;
maMembers.push_back(aMember);
}
+SvTreeListEntry* ScCheckListBox::FindEntry( SvTreeListEntry* pParent, const OUString& sNode )
+{
+ sal_uInt16 nRootPos = 0;
+ SvTreeListEntry* pEntry = pParent ? FirstChild( pParent ) : GetEntry( nRootPos );
+ while ( pEntry )
+ {
+ if ( sNode.equals(GetEntryText( pEntry )) )
+ return pEntry;
+
+ pEntry = pParent ? NextSibling( pEntry ) : GetEntry( ++nRootPos );
+ }
+ return NULL;
+}
+
+void ScCheckListBox::Init()
+{
+ mpCheckButton = new SvLBoxButtonData( this );
+ EnableCheckButton( mpCheckButton );
+ SetNodeDefaultImages();
+}
+
+sal_Bool ScCheckListBox::IsChecked( OUString& sName, SvTreeListEntry* pParent )
+{
+ SvTreeListEntry* pEntry = FindEntry( pParent, sName );
+ if ( pEntry && GetCheckButtonState( pEntry ) == SV_BUTTON_CHECKED)
+ return sal_True;
+ return sal_False;
+}
+
+void ScCheckListBox::CheckEntryPos( OUString& sName, SvTreeListEntry* pParent, sal_Bool bCheck )
+{
+ SvTreeListEntry* pEntry = FindEntry( pParent, sName );
+ if ( pEntry )
+ CheckEntryPos( pEntry, bCheck );
+}
+
+void ScCheckListBox::CheckEntryPos( SvTreeListEntry* pParent, sal_Bool bCheck )
+{
+ // currently pParent ( and *all* children ) are checked with state of bCheck
+ // *BUT* if this is not a Root node then bCheck here should also influence the
+ // ancestor hierarchy ( e.g. a child node checked or uncheck MAY need to check/uncheck
+ // the parent/grandparent node )
+ if ( pParent )
+ {
+ SetCheckButtonState(
+ pParent, bCheck ? SvButtonState( SV_BUTTON_CHECKED ) :
+ SvButtonState( SV_BUTTON_UNCHECKED ) );
+ }
+ SvTreeListEntry* pEntry = pParent ? FirstChild( pParent ) : First();
+ while ( pEntry )
+ {
+ CheckEntryPos( pEntry, bCheck );
+ pEntry = NextSibling( pEntry );
+ }
+}
+
+SvTreeListEntry* ScCheckListBox::CountCheckedEntries( SvTreeListEntry* pParent, sal_uLong& nCount ) const
+{
+ if ( pParent && GetCheckButtonState( pParent ) == SV_BUTTON_CHECKED )
+ nCount++;
+ // Iterate over the children
+ SvTreeListEntry* pEntry = pParent ? FirstChild( pParent ) : First();
+ while ( pEntry )
+ {
+ CountCheckedEntries( pEntry, nCount );
+ pEntry = NextSibling( pEntry );
+ }
+ return NULL;
+}
+
+sal_uInt16 ScCheckListBox::GetCheckedEntryCount() const
+{
+ sal_uLong nCount = 0;
+ CountCheckedEntries( NULL, nCount );
+ return nCount;
+}
+
+void ScCheckListBox::ExpandChildren( SvTreeListEntry* pParent )
+{
+ if ( pParent )
+ Expand( pParent );
+ // Iterate over the children
+ SvTreeListEntry* pEntry = pParent ? FirstChild( pParent ) : First();
+ while ( pEntry )
+ {
+ ExpandChildren( pEntry );
+ pEntry = NextSibling( pEntry );
+ }
+}
+
+void ScCheckListBox::KeyInput( const KeyEvent& rKEvt )
+{
+ const KeyCode& rKey = rKEvt.GetKeyCode();
+
+ if ( rKey.GetCode() == KEY_RETURN || rKey.GetCode() == KEY_SPACE )
+ {
+ SvTreeListEntry* pEntry = GetCurEntry();
+
+ if ( pEntry )
+ {
+ sal_Bool bCheck = ( GetCheckButtonState( pEntry ) == SV_BUTTON_CHECKED );
+ CheckEntryPos( pEntry, !bCheck );
+ if ( bCheck != ( GetCheckButtonState( pEntry ) == SV_BUTTON_CHECKED ) )
+ CheckButtonHdl();
+ }
+ }
+ else if ( GetEntryCount() )
+ SvTreeListBox::KeyInput( rKEvt );
+}
+
void ScCheckListMenuWindow::initMembers()
{
size_t n = maMembers.size();
@@ -1282,8 +1455,19 @@ void ScCheckListMenuWindow::initMembers()
maChecks.SetUpdateMode(false);
for (size_t i = 0; i < n; ++i)
{
- maChecks.InsertEntry(maMembers[i].maName);
- maChecks.CheckEntryPos(static_cast< sal_uInt16 >( i ), maMembers[i].mbVisible);
+ if ( !maMembers[ i ].mbDate )
+ {
+ maChecks.InsertEntry(maMembers[i].maName, NULL, sal_False, LISTBOX_APPEND, NULL,
+ SvLBoxButtonKind_enabledCheckbox );
+ }
+ // Expand all nodes of dates
+ // Needs better behaviour, what gets expanded how much etc. ( depending
+ // on the tree contents )
+ else if ( maMembers[ i ].mpParent == NULL )
+ {
+ maChecks.ExpandChildren( maChecks.FindEntry( NULL, maMembers[ i ].maName ) );
+ }
+ maChecks.CheckEntryPos( maMembers[i].maName, maMembers[i].mpParent, maMembers[i].mbVisible);
if (maMembers[i].mbVisible)
++nVisMemCount;
}
@@ -1323,8 +1507,16 @@ void ScCheckListMenuWindow::getResult(ResultType& rResult)
size_t n = maMembers.size();
for (size_t i = 0; i < n; ++i)
{
- bool bState = maChecks.IsChecked(static_cast< sal_uInt16 >( i ));
- aResult.insert(ResultType::value_type(maMembers[i].maName, bState));
+ if ( maMembers[i].mbLeaf )
+ {
+ bool bState = maChecks.IsChecked( maMembers[i].maName, maMembers[i].mpParent );
+ OUString sName;
+ if ( maMembers[i].mbDate )
+ sName = maMembers[i].maRealName;
+ else
+ sName = maMembers[i].maName;
+ aResult.insert(ResultType::value_type(sName, bState));
+ }
}
rResult.swap(aResult);
}
diff --git a/sc/source/ui/inc/checklistmenu.hxx b/sc/source/ui/inc/checklistmenu.hxx
index 305026d13e4b..ba8166b0949f 100644
--- a/sc/source/ui/inc/checklistmenu.hxx
+++ b/sc/source/ui/inc/checklistmenu.hxx
@@ -186,6 +186,24 @@ private:
ScMenuFloatingWindow* mpParentMenu;
};
+
+class ScCheckListBox : public SvTreeListBox
+{
+ SvLBoxButtonData* mpCheckButton;
+ SvTreeListEntry* CountCheckedEntries( SvTreeListEntry* pParent, sal_uLong& nCount ) const;
+ public:
+ ScCheckListBox( Window* pParent, WinBits nWinStyle = 0 ) : SvTreeListBox( pParent, nWinStyle ) { Init(); }
+ ScCheckListBox( Window* pParent, const ResId& rResId ) : SvTreeListBox( pParent, rResId ) { Init(); }
+ ~ScCheckListBox() { delete mpCheckButton; }
+ void Init();
+ void CheckEntryPos ( OUString& sName, SvTreeListEntry* pParent, sal_Bool bCheck = sal_True );
+ void CheckEntryPos ( SvTreeListEntry* pEntry, sal_Bool bCheck = sal_True );
+ sal_Bool IsChecked( OUString& sName, SvTreeListEntry* pParent );
+ SvTreeListEntry* FindEntry( SvTreeListEntry* pParent, const OUString& sNode );
+ sal_uInt16 GetCheckedEntryCount() const;
+ void ExpandChildren( SvTreeListEntry* pParent );
+ virtual void KeyInput( const KeyEvent& rKEvt );
+};
/**
* This class implements a popup window for field button, for quick access
* of hide-item list, and possibly more stuff related to field options.
@@ -225,6 +243,7 @@ public:
virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible();
void setMemberSize(size_t n);
+ void addDateMember(const OUString& rName, double nVal, bool bVisible);
void addMember(const OUString& rName, bool bVisible);
void initMembers();
void setConfig(const Config& rConfig);
@@ -255,10 +274,14 @@ protected:
private:
struct Member
{
- OUString maName;
+ OUString maName; // node name
+ OUString maRealName;
bool mbVisible;
+ bool mbDate;
+ bool mbLeaf;
Member();
+ SvTreeListEntry* mpParent;
};
class CancelButton : public ::CancelButton
@@ -299,7 +322,9 @@ private:
DECL_LINK( CheckHdl, SvTreeListBox* );
private:
- SvxCheckListBox maChecks;
+ SvTreeListEntry* findEntry( SvTreeListEntry* pParent, const OUString& rText );
+
+ ScCheckListBox maChecks;
TriStateBox maChkToggleAll;
ImageButton maBtnSelectSingle;
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
index 2b4e65784d61..dc13e38904eb 100644
--- a/sc/source/ui/view/gridwin.cxx
+++ b/sc/source/ui/view/gridwin.cxx
@@ -706,7 +706,10 @@ void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow)
bool bSelected = true;
if (!aSelected.empty())
bSelected = aSelected.count(aVal) > 0;
- mpAutoFilterPopup->addMember(aVal, bSelected);
+ if ( it->IsDate() )
+ mpAutoFilterPopup->addDateMember( aVal, it->GetValue(), bSelected );
+ else
+ mpAutoFilterPopup->addMember(aVal, bSelected);
}
mpAutoFilterPopup->initMembers();