xref: /trunk/main/svtools/inc/svtools/fmtfield.hxx (revision 86e1cf34)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #ifndef _FMTFIELD_HXX_
25 #define _FMTFIELD_HXX_
26 
27 #include "svtools/svtdllapi.h"
28 #include <vcl/spinfld.hxx>
29 #include <svl/zforlist.hxx>
30 
31 //#define REGEXP_SUPPORT
32 
33 #ifdef REGEXP_SUPPORT
34 	#ifndef _UNOTOOLS_TEXTSEARCH_HXX
35 	#include <unotools/textsearch.hxx>
36 	#endif
37 #else
38 	// use a hand-made regular expression parsing for the small expression we're interested in
39 	// as soon as OOo does have regular expression support, we can switch on the REGEXP_SUPPORT define
40 	namespace validation { class NumberValidator; }
41 #endif
42 
43 typedef sal_uInt16 FORMAT_CHANGE_TYPE;
44 #define FCT_KEYONLY			0x00		// only a new key was set
45 #define FCT_FORMATTER		0x01		// a new formatter was set, usually implies a change of the key, too
46 #define FCT_PRECISION		0x02		// a new precision was set
47 #define FCT_THOUSANDSSEP	0x03		// the thousands separator setting changed
48 
49 //------------------------------------------------------------------------------
50 class SVT_DLLPUBLIC FormattedField : public SpinField
51 {
52 private:
53 	// Da ein SvNumberFormatter eine ziemlich teure (sowohl zeit- als auch platz-maessig) Angelegenheit ist,
54 	// haelt sich nicht jedes Field, an dem kein Formatter gesetzt wurde, eine eigenen Instanz, sondern es gibt nur eine
55 	// einzige statische.
56 	class StaticFormatter
57 	{
58 		static SvNumberFormatter*	s_cFormatter;
59 		static sal_uLong				s_nReferences;
60 	public:
61 		StaticFormatter();
62 		~StaticFormatter();
63 
operator SvNumberFormatter*()64 		operator SvNumberFormatter* () { return GetFormatter(); }
65 		SVT_DLLPUBLIC SvNumberFormatter* GetFormatter();
66 	};
67 
68 protected:
69 	String		m_sLastValidText;
70 		// hat nichts mit dem current value zu tun, ist der letzte Text, der waehrend einer Eingabe als gueltig erkannt
71 		// wurde (also durch CheckText geprueft, nicht durch den Formatter gejagt)
72 	Selection	m_aLastSelection;
73 
74 	double				m_dMinValue;
75 	double				m_dMaxValue;
76 	sal_Bool				m_bHasMin : 1;
77 	sal_Bool				m_bHasMax : 1;
78 
79 	sal_Bool				m_bStrictFormat : 1;
80 
81 	sal_Bool				m_bValueDirty : 1;
82 	sal_Bool				m_bEnableEmptyField : 1;
83 	sal_Bool				m_bAutoColor : 1;
84     sal_Bool				m_bEnableNaN : 1;
85 	double				m_dCurrentValue;
86 	double				m_dDefaultValue;
87 
88 	sal_uLong				m_nFormatKey;
89 	SvNumberFormatter*	m_pFormatter;
90 	StaticFormatter		m_aStaticFormatter;
91 
92 	double				m_dSpinSize;
93 	double				m_dSpinFirst;
94 	double				m_dSpinLast;
95 
96 	// es macht einen Unterschied, ob man bei eingestellter Textformatierung beim LostFocus den aktuellen String durch
97 	// den Formatter jagt und das Ergebnis anzeigt oder erst aus dem String ein double macht, das formatiert und dann
98 	// ausgibt
99 	sal_Bool				m_bTreatAsNumber;
100 	// und mit den folgenden Members koennen wir das Ganze hier auch zur formatierten Text-Ausgabe benutzen ...
101 	String				m_sCurrentTextValue;
102 	String				m_sDefaultText;
103 
104 	// die bei der letzten Ausgabe-Operation vom Formatter gelieferte Farbe (nicht dass wir sie beachten wuerden, aber
105 	// man kann sie von aussen abfragen)
106 	Color*				m_pLastOutputColor;
107 
108     bool                m_bUseInputStringForFormatting;
109 
110 public:
111 	FormattedField(Window* pParent, WinBits nStyle = 0, SvNumberFormatter* pInitialFormatter = NULL, sal_Int32 nFormatKey = 0);
112 	FormattedField(Window* pParent, const ResId& rResId, SvNumberFormatter* pInitialFormatter = NULL, sal_Int32 nFormatKey = 0);
113 	virtual ~FormattedField();
114 
115 	// Min-/Max-Verwaltung
HasMinValue() const116 	sal_Bool	HasMinValue() const			{ return m_bHasMin; }
ClearMinValue()117 	void	ClearMinValue()				{ m_bHasMin = sal_False; }
118 	void	SetMinValue(double dMin);
GetMinValue() const119 	double	GetMinValue() const			{ return m_dMinValue; }
120 
HasMaxValue() const121 	sal_Bool	HasMaxValue() const			{ return m_bHasMax; }
ClearMaxValue()122 	void	ClearMaxValue()				{ m_bHasMax = sal_False; }
123 	void	SetMaxValue(double dMax);
GetMaxValue() const124 	double	GetMaxValue() const			{ return m_dMaxValue; }
125 
126 	// aktueller Wert
127 	virtual void	SetValue(double dVal);
128 	virtual double	GetValue();
129 		// die Standard-Implementierung jagt die Eingabe jeweils durch den Formatter, so einer vorhanden ist
130 
131 	void	GetColor() const;
132 
133 	void	SetTextValue(const XubString& rText);
134 		// der String wird in ein double umgewandelt (durch den Formatter) und anschliessen in SetValue gesteckt
135 
IsEmptyFieldEnabled() const136 	sal_Bool	IsEmptyFieldEnabled() const			{ return m_bEnableEmptyField; }
137 	void	EnableEmptyField(sal_Bool bEnable);
138 		// wenn nicht enabled, wird beim Verlassen des Feldes der Text auf den letzten gueltigen zurueckgesetzt
139 
SetDefaultValue(double dDefault)140 	void	SetDefaultValue(double dDefault)	{ m_dDefaultValue = dDefault; m_bValueDirty = sal_True; }
141 		// wenn der aktuelle String ungueltig ist, liefert GetValue() diesen Default-Wert
GetDefaultValue() const142 	double	GetDefaultValue() const				{ return m_dDefaultValue; }
143 
144 	// Einstellungen fuer das Format
GetFormatKey() const145 	sal_uLong	GetFormatKey() const				{ return m_nFormatKey; }
146 	void	SetFormatKey(sal_uLong nFormatKey);
147 
GetFormatter() const148 	SvNumberFormatter*	GetFormatter() const	{ return m_pFormatter; }
149 	void	SetFormatter(SvNumberFormatter* pFormatter, sal_Bool bResetFormat = sal_True);
150 		// wenn bResetFormat sal_False ist, wird versucht, das alte eingestellte Format mit 'hinueberzuretten' (teuer, wenn es sich nicht
151 		// um eines der Standard-Formate handelt, die in allen Formattern gleich sind)
152 		// wenn sal_True, wird als neuer FormatKey 0 gesetzt
153 
154 	sal_Bool	GetThousandsSep() const;
155 	void	SetThousandsSep(sal_Bool _bUseSeparator);
156 		// the is no check if the current format is numeric, so be cautious when calling these functions
157 
158 	sal_uInt16	GetDecimalDigits() const;
159 	void	SetDecimalDigits(sal_uInt16 _nPrecision);
160 		// the is no check if the current format is numeric, so be cautious when calling these functions
161 
StandardFormatter()162 	SvNumberFormatter*	StandardFormatter() { return m_aStaticFormatter; }
163 		// Wenn man keinen eigenen Formatter explizit anlegen will, kann man diesen hier in SetFormatter stecken ...
164 		// Das hier gelieferte Objekt wird allerdings zwischen allen Instanzen der Klasse geteilt (aus Zeit- und Platzgruenden),
165 		// also ist etwas Vorsicht angebracht ...
166 
167 	void		GetFormat(XubString& rFormatString, LanguageType& eLang) const;
168 	sal_Bool		SetFormat(const XubString& rFormatString, LanguageType eLang);
169 		// sal_False, wenn der FormatString nicht gesetzt werden konnte (also wahrscheinlich ungueltig ist)
170 
IsStrictFormat() const171 	sal_Bool	IsStrictFormat() const				{ return m_bStrictFormat; }
SetStrictFormat(sal_Bool bEnable)172 	void	SetStrictFormat(sal_Bool bEnable)		{ m_bStrictFormat = bEnable; }
173 		// Formatueberpruefung waehrend der Eingabe ?
174 
175 	// Spin-Handling
176 	virtual void Up();
177 	virtual void Down();
178 		// Standard-Implementierung : hoch- oder runterzaehlen des aktuellen double einfach um die gesetzte SpinSize
179 	virtual void First();
180 	virtual void Last();
181 		// Standard-Implementierung : aktuelles double setzen auf eingestellten first respektive last value
182 
SetSpinSize(double dStep)183 	void	SetSpinSize(double dStep)	{ m_dSpinSize = dStep; }
GetSpinSize() const184 	double	GetSpinSize() const			{ return m_dSpinSize; }
185 
SetSpinFirst(double dFirst)186 	void	SetSpinFirst(double dFirst)	{ m_dSpinFirst = dFirst; }
GetSpinFirst() const187 	double	GetSpinFirst() const		{ return m_dSpinFirst; }
188 
SetSpinLast(double dLast)189 	void	SetSpinLast(double dLast)	{ m_dSpinLast = dLast; }
GetSpinLast() const190 	double	GetSpinLast() const			{ return m_dSpinLast; }
191 
TreatingAsNumber() const192 	sal_Bool	TreatingAsNumber() const	{ return m_bTreatAsNumber; }
TreatAsNumber(sal_Bool bDoSo)193 	void	TreatAsNumber(sal_Bool bDoSo) { m_bTreatAsNumber = bDoSo; }
194 
195 public:
196 	virtual void SetText( const XubString& rStr );
197     virtual void SetText( const XubString& rStr, const Selection& rNewSelection );
198 	void	SetValidateText(const XubString& rText, const String* pErrorText = NULL);
199 
200 	// die folgenden Methoden sind interesant, wenn m_bTreatAsNumber auf sal_False sitzt
201 	/**	nehmen wir mal an, irgendjemand will das ganze schoene double-Handling gar nicht haben, sondern
202 		einfach den Text formatiert ausgeben ...
203 		(der Text wird einfach nur durch den Formatter gejagt und dann gesetzt)
204 	*/
205 	void SetTextFormatted(const XubString& rText);
206 	String	GetTextValue() const;
207 
SetDefaultText(const XubString & rDefault)208 	void	SetDefaultText(const XubString& rDefault) { m_sDefaultText = rDefault; }
GetDefaultText() const209 	String	GetDefaultText() const { return m_sDefaultText; }
210 
211 	// die bei der letzten Ausgabe-Operation vom Formatter gelieferte Farbe (Ausgabe-Operationen werden getriggert durch
212 	// SetValue, SetTextValue, SetTextFormatted, also indirekt eventuell auch durch SetMin-/-MaxValue)
GetLastOutputColor() const213 	Color*	GetLastOutputColor() const { return m_pLastOutputColor; }
214 
215 	/** reformats the current text. Interesting if the user entered some text in an "input format", and
216 		this should be formatted in the "output format" (which may differ, e.g. by additional numeric
217 		digits or such).
218 	*/
219 	void	Commit();
220 
221 	// enable automatic coloring. if set to sal_True, and the format the field is working with for any current value
222 	// says that it has to be painted in a special color (e.g. a format where negative numbers should be printed
223 	// red), the text is painted with that color automatically.
224 	// The color used is the same as returned by GetLastOutputColor()
225 	void	SetAutoColor(sal_Bool _bAutomatic);
GetAutoColor() const226 	sal_Bool	GetAutoColor() const { return m_bAutoColor; }
227 
228     /** enables handling of not-a-number value.
229 
230         When this is set to <FALSE/> (the default), then invalid inputs (i.e. text which cannot be
231         intepreted, according to the current formatting) will be handled as if the default value
232         has been entered. GetValue the will return this default value.
233 
234         When set to <TRUE/>, then GetValue will return NaN (not a number, see <method scope="rtl::math">isNan</method>)
235         when the current input is invalid.
236 
237         Note that setting this to <TRUE/> implies that upon leaving the control, the input
238         will *not* be corrected to a valid value. For example, if the user enters "foo" in the
239         control, and then tabs out of it, the text "foo" will persist, and GetValue will
240         return NaN in subsequent calls.
241     */
242     void    EnableNotANumber( sal_Bool _bEnable );
IsNotANumberEnabled() const243     sal_Bool    IsNotANumberEnabled( ) const { return m_bEnableNaN; }
244 
245     /** When being set to true, the strings in the field are formatted using the
246         InputLine format.  That's also what you get in Calc when you edit a cell
247         using F2
248      */
249     void    UseInputStringForFormatting( bool bUseInputStr = true );
250     bool    IsUsingInputStringForFormatting() const;
251 
252 protected:
253 	virtual long Notify(NotifyEvent& rNEvt);
254 	virtual void Modify();
255 
256 	// CheckText ueberschreiben fuer Ueberpruefung zur Eingabezeit
CheckText(const XubString &) const257 	virtual sal_Bool CheckText(const XubString&) const { return sal_True; }
258 
259 	// any aspect of the current format has changed
260 	virtual void FormatChanged(FORMAT_CHANGE_TYPE nWhat);
261 
262 	void ImplSetTextImpl(const XubString& rNew, Selection* pNewSel);
263 	void ImplSetValue(double dValue, sal_Bool bForce);
264 	sal_Bool ImplGetValue(double& dNewVal);
265 
266 	void ImplSetFormatKey(sal_uLong nFormatKey);
267 		// SetFormatKey without FormatChanged notification
268 
CreateFormatter()269 	virtual SvNumberFormatter*	CreateFormatter() { SetFormatter(StandardFormatter()); return m_pFormatter; }
ImplGetFormatter() const270 	SvNumberFormatter*	ImplGetFormatter() const { return m_pFormatter ? m_pFormatter : ((FormattedField*)this)->CreateFormatter(); }
271 
272 	long PreNotify(NotifyEvent& rNEvt);
273 
274 	virtual void ReFormat();
275 };
276 
277 //------------------------------------------------------------------------------
278 class SVT_DLLPUBLIC DoubleNumericField : public FormattedField
279 {
280 protected:
281 #ifdef REGEXP_SUPPORT
282 	::utl::TextSearch*				m_pConformanceTester;
283 #else
284 	validation::NumberValidator*	m_pNumberValidator;
285 #endif
286 
287 public:
DoubleNumericField(Window * pParent,WinBits nStyle=0)288 	DoubleNumericField(Window* pParent, WinBits nStyle = 0)
289 		:FormattedField(pParent, nStyle)
290 #ifdef REGEXP_SUPPORT
291 		,m_pConformanceTester( NULL )
292 #else
293 		,m_pNumberValidator( NULL )
294 #endif
295 	{
296         ResetConformanceTester();
297 	}
298 
DoubleNumericField(Window * pParent,const ResId & rResId)299 	DoubleNumericField(Window* pParent, const ResId& rResId)
300 		:FormattedField(pParent, rResId)
301 #ifdef REGEXP_SUPPORT
302 		,m_pConformanceTester( NULL )
303 #else
304 		,m_pNumberValidator( NULL )
305 #endif
306 	{
307         ResetConformanceTester();
308 	}
309 	virtual ~DoubleNumericField();
310 
311 protected:
312 	virtual sal_Bool CheckText(const XubString& sText) const;
313 
314 	virtual void FormatChanged(FORMAT_CHANGE_TYPE nWhat);
315 	void ResetConformanceTester();
316 };
317 
318 //==============================================================================
319 #define FCT_CURRENCY_SYMBOL		0x10
320 #define FCT_CURRSYM_POSITION	0x20
321 
322 //------------------------------------------------------------------------------
323 class DoubleCurrencyField : public FormattedField
324 {
325 	XubString	m_sCurrencySymbol;
326 	sal_Bool		m_bPrependCurrSym;
327 	sal_Bool		m_bChangingFormat;
328 
329 public:
330 	DoubleCurrencyField(Window* pParent, WinBits nStyle = 0);
331 	DoubleCurrencyField(Window* pParent, const ResId& rResId);
332 
getCurrencySymbol() const333 	XubString	getCurrencySymbol() const { return m_sCurrencySymbol; }
334 	void		setCurrencySymbol(const XubString& _sSymbol);
335 
getPrependCurrSym() const336 	sal_Bool		getPrependCurrSym() const { return m_bPrependCurrSym; }
337 	void		setPrependCurrSym(sal_Bool _bPrepend);
338 
339 protected:
340 	virtual void FormatChanged(FORMAT_CHANGE_TYPE nWhat);
341 
342 	void UpdateCurrencyFormat();
343 };
344 
345 #endif // _FMTFIELD_HXX_
346 
347