Files
libreoffice/sc/source/core/data/dpitemdata.cxx
Kohei Yoshida f2ac4ff660 fdo#51266: Properly set pivot item 'empty' on empty cells.
Or else it would re-use the last non-empty cell value which is wrong.

Change-Id: I3feab09a54e93150a7b6a9e9b4b540327f2ab5c5
2012-07-03 14:14:08 -04:00

383 lines
9.1 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Version: MPL 1.1 / GPLv3+ / LGPLv3+
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License or as specified alternatively below. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Major Contributor(s):
* Copyright (C) 2012 Kohei Yoshida <kohei.yoshida@suse.com>
*
* All Rights Reserved.
*
* For minor contributions see the git repository.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 3 or later (the "GPLv3+"), or
* the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
* in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
* instead of those above.
*/
#include "dpitemdata.hxx"
#include "document.hxx"
#include "dpobject.hxx"
#include "cell.hxx"
#include "globstr.hrc"
#include "dptabdat.hxx"
#include "rtl/math.hxx"
const sal_Int32 ScDPItemData::DateFirst = -1;
const sal_Int32 ScDPItemData::DateLast = 10000;
sal_Int32 ScDPItemData::Compare(const ScDPItemData& rA, const ScDPItemData& rB)
{
if (rA.meType != rB.meType)
{
// group value, value and string in this order.
return rA.meType < rB.meType ? -1 : 1;
}
switch (rA.meType)
{
case GroupValue:
{
if (rA.maGroupValue.mnGroupType == rB.maGroupValue.mnGroupType)
{
if (rA.maGroupValue.mnValue == rB.maGroupValue.mnValue)
return 0;
return rA.maGroupValue.mnValue < rB.maGroupValue.mnValue ? -1 : 1;
}
return rA.maGroupValue.mnGroupType < rB.maGroupValue.mnGroupType ? -1 : 1;
}
case Value:
case RangeStart:
{
if (rA.mfValue == rB.mfValue)
return 0;
return rA.mfValue < rB.mfValue ? -1 : 1;
}
case String:
case Error:
if (rA.mpString == rB.mpString)
// strings may be interned.
return 0;
return ScGlobal::GetCollator()->compareString(rA.GetString(), rB.GetString());
default:
;
}
return 0;
}
ScDPItemData::ScDPItemData() :
mfValue(0.0), meType(Empty), mbStringInterned(false) {}
ScDPItemData::ScDPItemData(const ScDPItemData& r) :
meType(r.meType), mbStringInterned(r.mbStringInterned)
{
switch (r.meType)
{
case String:
case Error:
mpString = mbStringInterned ? r.mpString : new rtl::OUString(*r.mpString);
break;
case Value:
case RangeStart:
mfValue = r.mfValue;
break;
case GroupValue:
maGroupValue.mnGroupType = r.maGroupValue.mnGroupType;
maGroupValue.mnValue = r.maGroupValue.mnValue;
break;
case Empty:
default:
mfValue = 0.0;
}
}
void ScDPItemData::DisposeString()
{
if (!mbStringInterned)
{
if (meType == String || meType == Error)
delete mpString;
}
mbStringInterned = false;
}
ScDPItemData::ScDPItemData(const rtl::OUString& rStr) :
mpString(new rtl::OUString(rStr)), meType(String), mbStringInterned(false) {}
ScDPItemData::ScDPItemData(sal_Int32 nGroupType, sal_Int32 nValue) :
meType(GroupValue), mbStringInterned(false)
{
maGroupValue.mnGroupType = nGroupType;
maGroupValue.mnValue = nValue;
}
ScDPItemData::~ScDPItemData()
{
DisposeString();
}
ScDPItemData::Type ScDPItemData::GetType() const
{
return static_cast<Type>(meType);
}
void ScDPItemData::SetEmpty()
{
DisposeString();
meType = Empty;
}
void ScDPItemData::SetString(const rtl::OUString& rS)
{
DisposeString();
mpString = new rtl::OUString(rS);
meType = String;
}
void ScDPItemData::SetString(const rtl::OUString* pS)
{
DisposeString();
mpString = pS;
meType = String;
mbStringInterned = true;
}
void ScDPItemData::SetValue(double fVal)
{
DisposeString();
mfValue = fVal;
meType = Value;
}
void ScDPItemData::SetRangeStart(double fVal)
{
DisposeString();
mfValue = fVal;
meType = RangeStart;
}
void ScDPItemData::SetRangeFirst()
{
DisposeString();
rtl::math::setInf(&mfValue, true);
meType = RangeStart;
}
void ScDPItemData::SetRangeLast()
{
DisposeString();
rtl::math::setInf(&mfValue, false);
meType = RangeStart;
}
void ScDPItemData::SetErrorString(const rtl::OUString* pS)
{
SetString(pS);
meType = Error;
}
bool ScDPItemData::IsCaseInsEqual(const ScDPItemData& r) const
{
if (meType != r.meType)
return false;
switch (meType)
{
case Value:
case RangeStart:
return rtl::math::approxEqual(mfValue, r.mfValue);
case GroupValue:
return maGroupValue.mnGroupType == r.maGroupValue.mnGroupType &&
maGroupValue.mnValue == r.maGroupValue.mnValue;
default:
;
}
if (mbStringInterned && r.mbStringInterned)
return mpString == r.mpString;
return ScGlobal::GetpTransliteration()->isEqual(GetString(), r.GetString());
}
bool ScDPItemData::operator== (const ScDPItemData& r) const
{
if (meType != r.meType)
return false;
switch (meType)
{
case Value:
case RangeStart:
return rtl::math::approxEqual(mfValue, r.mfValue);
case GroupValue:
return maGroupValue.mnGroupType == r.maGroupValue.mnGroupType &&
maGroupValue.mnValue == r.maGroupValue.mnValue;
default:
;
}
// need exact equality until we have a safe case insensitive string hash
return GetString() == r.GetString();
}
bool ScDPItemData::operator!= (const ScDPItemData& r) const
{
return !operator== (r);
}
bool ScDPItemData::operator< (const ScDPItemData& r) const
{
return Compare(*this, r) == -1;
}
ScDPItemData& ScDPItemData::operator= (const ScDPItemData& r)
{
DisposeString();
meType = r.meType;
mbStringInterned = false;
switch (r.meType)
{
case String:
case Error:
mpString = r.mbStringInterned ? r.mpString : new rtl::OUString(*r.mpString);
mbStringInterned = r.mbStringInterned;
break;
case Value:
case RangeStart:
mfValue = r.mfValue;
break;
case GroupValue:
maGroupValue.mnGroupType = r.maGroupValue.mnGroupType;
maGroupValue.mnValue = r.maGroupValue.mnValue;
break;
case Empty:
default:
mfValue = 0.0;
}
return *this;
}
sal_uInt8 ScDPItemData::GetCellType() const
{
switch (meType)
{
case Error:
return SC_VALTYPE_ERROR;
case Empty:
return SC_VALTYPE_EMPTY;
case Value:
return SC_VALTYPE_VALUE;
default:
;
}
return SC_VALTYPE_STRING;
}
#if DEBUG_PIVOT_TABLE
void ScDPItemData::Dump(const char* msg) const
{
printf("--- (%s)\n", msg);
switch (meType)
{
case Empty:
printf("empty\n");
break;
case Error:
printf("error: %s\n",
rtl::OUStringToOString(*mpString, RTL_TEXTENCODING_UTF8).getStr());
break;
case GroupValue:
printf("group value: group type = %d value = %d\n",
maGroupValue.mnGroupType, maGroupValue.mnValue);
break;
case String:
printf("string: %s\n",
rtl::OUStringToOString(*mpString, RTL_TEXTENCODING_UTF8).getStr());
break;
case Value:
printf("value: %g\n", mfValue);
break;
case RangeStart:
printf("range start: %g\n", mfValue);
break;
default:
printf("unknown type\n");
}
printf("---\n");
}
#endif
bool ScDPItemData::IsEmpty() const
{
return meType == Empty;
}
bool ScDPItemData::IsValue() const
{
return meType == Value;
}
rtl::OUString ScDPItemData::GetString() const
{
switch (meType)
{
case String:
case Error:
return *mpString;
case Value:
return rtl::OUString::valueOf(mfValue);
case GroupValue:
case RangeStart:
return rtl::OUString::createFromAscii("fail");
case Empty:
default:
;
}
return rtl::OUString();
}
double ScDPItemData::GetValue() const
{
if (meType == Value || meType == RangeStart)
return mfValue;
return 0.0;
}
ScDPItemData::GroupValueAttr ScDPItemData::GetGroupValue() const
{
if (meType == GroupValue)
return maGroupValue;
GroupValueAttr aGV;
aGV.mnGroupType = -1;
aGV.mnValue = -1;
return aGV;
}
bool ScDPItemData::HasStringData() const
{
return meType == String || meType == Error;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */