1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: fmsrcimp.hxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
34 #include "fmtools.hxx"
35 #include <vos/thread.hxx>
36 #include <osl/mutex.hxx>
37 #include <com/sun/star/awt/XTextComponent.hpp>
38 #include <com/sun/star/awt/XCheckBox.hpp>
39 #include <com/sun/star/awt/XListBox.hpp>
40 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
41 #include <com/sun/star/util/XNumberFormatter.hpp>
42 #include <comphelper/stl_types.hxx>
43 #include <cppuhelper/implbase1.hxx>
44 #include <unotools/charclass.hxx>
45 #include <unotools/collatorwrapper.hxx>
46 #include "svx/svxdllapi.h"
48 // ===================================================================================================
51 SV_DECL_OBJARR(SvInt32Array
, sal_Int32
, 16, 16)
53 // ===================================================================================================
54 // = class FmSearchThread - wie der Name schon sagt
55 // ===================================================================================================
58 class FmSearchThread
: public ::vos::OThread
60 FmSearchEngine
* m_pEngine
;
61 Link m_aTerminationHdl
;
63 virtual void SAL_CALL
run();
64 virtual void SAL_CALL
onTerminated();
67 FmSearchThread(FmSearchEngine
* pEngine
) : m_pEngine(pEngine
) { }
68 void setTerminationHandler(Link aHdl
) { m_aTerminationHdl
= aHdl
; }
71 // ===================================================================================================
72 // = struct FmSearchProgress - diese Struktur bekommt der Owner der SearchEngine fuer Status-Updates
73 // = (und am Ende der Suche)
74 // ===================================================================================================
76 struct FmSearchProgress
78 enum STATE
{ STATE_PROGRESS
, STATE_PROGRESS_COUNTING
, STATE_CANCELED
, STATE_SUCCESSFULL
, STATE_NOTHINGFOUND
, STATE_ERROR
};
79 // (Bewegung auf neuen Datensatz; Fortschritt beim Zaehlen von Datensaetzen; abgebrochen; Datensatz gefunden;
80 // nichts gefunden, irgendein nicht zu handelnder Fehler)
83 // aktueller Datensatz - immer gueltig (ist zum Beispiel bei Abbrechen auch fuer das Weitersuchen interesant)
84 sal_uInt32 nCurrentRecord
;
85 // Ueberlauf - nur gueltig bei STATE_PROGRESS
88 // die Position des Such-Cursors - bei STATE_SUCCESSFULL, STATE_CANCELED und STATE_NOTHING_FOUND gueltig
89 ::com::sun::star::uno::Any aBookmark
;
90 // das Feld, in dem der Text gefunden wurde - bei STATE_SUCCESSFULL gueltig
91 sal_Int32 nFieldIndex
;
94 // ===================================================================================================
95 // = class FmRecordCountListener - Hilfsklasse fuer FmSearchEngine, lauscht an einem Cursor und teilt
96 // = Aenderungem im RecordCount mit
97 // ===================================================================================================
99 class FmRecordCountListener
: public ::cppu::WeakImplHelper1
< ::com::sun::star::beans::XPropertyChangeListener
>
102 Link m_lnkWhoWantsToKnow
;
103 ::com::sun::star::uno::Reference
< ::com::sun::star::beans::XPropertySet
> m_xListening
;
107 Link
SetPropChangeHandler(const Link
& lnk
);
111 FmRecordCountListener(const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XResultSet
>& dbcCursor
);
112 // the set has to support the sdb::ResultSet service
113 virtual ~FmRecordCountListener();
115 // DECLARE_UNO3_AGG_DEFAULTS(FmPropertyListener, UsrObject);
116 // virtual sal_Bool queryInterface(::com::sun::star::uno::Uik aUik, ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rOut);
118 // ::com::sun::star::lang::XEventListener
119 virtual void SAL_CALL
disposing(const ::com::sun::star::lang::EventObject
& Source
) throw(::com::sun::star::uno::RuntimeException
);
121 // ::com::sun::star::beans::XPropertyChangeListener
122 virtual void SAL_CALL
propertyChange(const ::com::sun::star::beans::PropertyChangeEvent
& evt
) throw(::com::sun::star::uno::RuntimeException
);
127 void NotifyCurrentCount();
131 // ===================================================================================================
132 // = class FmSearchEngine - Impl-Klasse fuer FmSearchDialog
133 // ===================================================================================================
136 // We have three possible control types we may search in, determined by the supported interfaces : ::com::sun::star::awt::XTextComponent, ::com::sun::star::awt::XListBox, ::com::sun::star::awt::XCheckBox.
137 // While searching we don't want to do this distinction for every control in every round. So we need some helpers.
138 class ControlTextWrapper
141 ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
> m_xControl
;
144 ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
> getControl() const{ return m_xControl
; }
146 ControlTextWrapper(const ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
>& _xControl
) { m_xControl
= _xControl
; }
147 virtual ~ControlTextWrapper() { }
149 virtual ::rtl::OUString
getCurrentText() const = 0;
151 class SimpleTextWrapper
: public ControlTextWrapper
153 ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XTextComponent
> m_xText
;
155 SimpleTextWrapper(const ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XTextComponent
>& _xText
);
156 virtual ::rtl::OUString
getCurrentText() const;
158 class ListBoxWrapper
: public ControlTextWrapper
160 ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XListBox
> m_xBox
;
162 ListBoxWrapper(const ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XListBox
>& _xBox
);
163 virtual ::rtl::OUString
getCurrentText() const;
165 class CheckBoxWrapper
: public ControlTextWrapper
167 ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XCheckBox
> m_xBox
;
169 CheckBoxWrapper(const ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XCheckBox
>& _xBox
);
170 virtual ::rtl::OUString
getCurrentText() const;
174 enum FMSEARCH_MODE
{ SM_BRUTE
, SM_ALLOWSCHEDULE
, SM_USETHREAD
};
176 DECLARE_STL_VECTOR( ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
>, InterfaceArray
);
178 class SVX_DLLPUBLIC FmSearchEngine
180 friend class FmSearchThread
;
182 enum SEARCH_RESULT
{ SR_FOUND
, SR_NOTFOUND
, SR_ERROR
, SR_CANCELED
};
183 enum SEARCHFOR_TYPE
{ SEARCHFOR_STRING
, SEARCHFOR_NULL
, SEARCHFOR_NOTNULL
};
185 // zugrundeliegende Daten
186 CursorWrapper m_xSearchCursor
;
187 SvInt32Array m_arrFieldMapping
;
188 // da der Iterator durchaus mehr Spalten haben kann, als ich eigentlich verwalte (in meiner Feld-Listbox),
189 // muss ich mir hier ein Mapping dieser ::com::sun::star::form-Schluessel auf die Indizies der entsprechenden Spalten im Iterator halten
192 ::com::sun::star::uno::Reference
< ::com::sun::star::util::XNumberFormatsSupplier
> m_xFormatSupplier
;
193 ::com::sun::star::uno::Reference
< ::com::sun::star::util::XNumberFormatter
> m_xFormatter
;
195 CharClass m_aCharacterClassficator
;
196 CollatorWrapper m_aStringCompare
;
198 // die Sammlung aller interesanten Felder (bzw. ihre ::com::sun::star::data::XDatabaseVariant-Interfaces und ihre FormatKeys)
201 ::com::sun::star::uno::Reference
< ::com::sun::star::sdb::XColumn
> xContents
;
202 sal_uInt32 nFormatKey
;
203 sal_Bool bDoubleHandling
;
206 DECLARE_STL_VECTOR(FieldInfo
, FieldCollection
);
207 FieldCollection m_arrUsedFields
;
208 sal_Int32 m_nCurrentFieldIndex
; // der letzte Parameter von RebuildUsedFields, ermoeglicht mir Checks in FormatField
210 DECLARE_STL_VECTOR(svxform::ControlTextWrapper
*, ControlTextSuppliers
);
211 ControlTextSuppliers m_aControlTexts
;
213 sal_Bool m_bUsingTextComponents
;
214 CursorWrapper m_xOriginalIterator
;
215 CursorWrapper m_xClonedIterator
;
217 // Daten fuer Entscheidung, in welchem Feld ich ein "Found" akzeptiere
218 ::com::sun::star::uno::Any m_aPreviousLocBookmark
; // Position, an der ich zuletzt fuendig war
219 FieldCollectionIterator m_iterPreviousLocField
; // dito Feld
221 // Kommunikation mit dem Thread, der die eigentliche Suche durchfuehrt
222 ::rtl::OUString m_strSearchExpression
; // Hinrichtung
223 SEARCHFOR_TYPE m_eSearchForType
; // dito
224 SEARCH_RESULT m_srResult
; // Rueckrichtung
226 // der Link, dem ich Fortschritte und Ergebnisse mitteile
227 Link m_aProgressHandler
;
228 sal_Bool m_bSearchingCurrently
: 1; // laeuft gerade eine (asynchrone) Suche ?
229 sal_Bool m_bCancelAsynchRequest
: 1; // soll abgebrochen werden ?
230 ::osl::Mutex m_aCancelAsynchAccess
; // Zugriff auf m_bCancelAsynchRequest (eigentlich nur bei
231 // m_eMode == SM_USETHREAD interesant)
232 FMSEARCH_MODE m_eMode
; //CHINA001 FmSearchDialog::SEARCH_MODE m_eMode; // der aktuelle Modus
233 // der aktuelle Modus
235 // Parameter fuer die Suche
236 sal_Bool m_bFormatter
: 1; // Feldformatierung benutzen
237 sal_Bool m_bForward
: 1; // Richtung
238 sal_Bool m_bWildcard
: 1; // Platzhalter-Suche ?
239 sal_Bool m_bRegular
: 1; // regulaerer Ausdruck
240 sal_Bool m_bLevenshtein
: 1; // Levenshtein-Suche
241 sal_Bool m_bTransliteration
: 1; // Levenshtein-Suche
243 sal_Bool m_bLevRelaxed
: 1; // Parameter fuer Levenshtein-Suche
244 sal_uInt16 m_nLevOther
;
245 sal_uInt16 m_nLevShorter
;
246 sal_uInt16 m_nLevLonger
;
248 sal_uInt16 m_nPosition
; // wenn nicht regulaer oder lev, dann einer der MATCHING_...-Werte
250 sal_Int32 m_nTransliterationFlags
;
255 SVX_DLLPRIVATE sal_Bool
CancelRequested(); // liefert eine durch m_aCancelAsynchAccess gesicherte Auswertung von m_bCancelAsynchRequest
258 void SetCaseSensitive(sal_Bool bSet
);
259 sal_Bool
GetCaseSensitive() const;
261 void SetFormatterUsing(sal_Bool bSet
); // das ist etwas umfangreicher, deshalb kein hier inline ....
262 sal_Bool
GetFormatterUsing() const { return m_bFormatter
; }
264 void SetDirection(sal_Bool bForward
) { m_bForward
= bForward
; }
265 sal_Bool
GetDirection() const { return m_bForward
; }
267 void SetWildcard(sal_Bool bSet
) { m_bWildcard
= bSet
; }
268 sal_Bool
GetWildcard() const { return m_bWildcard
; }
270 void SetRegular(sal_Bool bSet
) { m_bRegular
= bSet
; }
271 sal_Bool
GetRegular() const { return m_bRegular
; }
273 void SetLevenshtein(sal_Bool bSet
) { m_bLevenshtein
= bSet
; }
274 sal_Bool
GetLevenshtein() const { return m_bLevenshtein
; }
276 void SetIgnoreWidthCJK(sal_Bool bSet
);
277 sal_Bool
GetIgnoreWidthCJK() const;
279 void SetTransliteration(sal_Bool bSet
) { m_bTransliteration
= bSet
; }
280 sal_Bool
GetTransliteration() const { return m_bTransliteration
; }
282 void SetLevRelaxed(sal_Bool bSet
) { m_bLevRelaxed
= bSet
; }
283 sal_Bool
GetLevRelaxed() const { return m_bLevRelaxed
; }
284 void SetLevOther(sal_uInt16 nHowMuch
) { m_nLevOther
= nHowMuch
; }
285 sal_uInt16
GetLevOther() const { return m_nLevOther
; }
286 void SetLevShorter(sal_uInt16 nHowMuch
) { m_nLevShorter
= nHowMuch
; }
287 sal_uInt16
GetLevShorter() const { return m_nLevShorter
; }
288 void SetLevLonger(sal_uInt16 nHowMuch
) { m_nLevLonger
= nHowMuch
; }
289 sal_uInt16
GetLevLonger() const { return m_nLevLonger
; }
290 // die ganzen Lev-Werte werden nur bei m_bLevenshtein==sal_True beachtet
292 void SetTransliterationFlags(sal_Int32 _nFlags
) { m_nTransliterationFlags
= _nFlags
; }
293 sal_Int32
GetTransliterationFlags() const { return m_nTransliterationFlags
; }
295 void SetPosition(sal_uInt16 nValue
) { m_nPosition
= nValue
; }
296 sal_uInt16
GetPosition() const { return m_nPosition
; }
297 // Position wird bei m_bWildCard==sal_True nicht beachtet
299 FMSEARCH_MODE
GetSearchMode() const { return m_eMode
; }
302 /** zwei Constructoren, beide analog zu denen des FmSearchDialog, Erklaerung siehe also dort ....
303 xCursor muss jeweils den ::com::sun::star::data::DatabaseCursor-Service implementieren.
304 wenn eMode == SM_USETHREAD, sollte ein ProgressHandler gesetzt sein, da dann die Ergebnisuebermittlung ueber diesen
306 Ist eMode != SM_USETHREAD, kehren SearchNext und StarOver nicht zurueck, bevor die Suche (erfolgreich oder nicht) beendet
307 wurde, dann kann man das Ergebnis danach abfragen. Ist zusaetzlich der ProgressHandler gesetzt, wird dieser fuer jeden neuen
308 Datensatz sowie am Ende der Suche aufgerufen.
311 const ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XMultiServiceFactory
>& _rxORB
,
312 const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XResultSet
>& xCursor
,
313 const ::rtl::OUString
& strVisibleFields
,
314 const ::com::sun::star::uno::Reference
< ::com::sun::star::util::XNumberFormatsSupplier
>& xFormat
,
315 FMSEARCH_MODE eMode
);//CHINA001 FmSearchDialog::SEARCH_MODE eMode);
317 const ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XMultiServiceFactory
>& _rxORB
,
318 const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XResultSet
>& xCursor
,
319 const ::rtl::OUString
& strVisibleFields
,
320 const InterfaceArray
& arrFields
,
321 FMSEARCH_MODE eMode
); //CHINA001 FmSearchDialog::SEARCH_MODE eMode);
323 virtual ~FmSearchEngine();
325 /** der Link wird fuer jeden Datensatz und nach Beendigung der Suche aufgerufen, Parameter ist ein Zeiger auf
326 eine FmSearchProgress-Struktur
327 der Handler sollte auf jeden Fall Thread-sicher sein
329 void SetProgressHandler(Link aHdl
) { m_aProgressHandler
= aHdl
; }
331 /// das naechste Vorkommen suchen (Werte fuer nDirection siehe DIRECTION_*-defines)
332 void SearchNext(const ::rtl::OUString
& strExpression
);
333 /// analogous, search for "NULL" (_bSearchForNull==sal_True) or "not NULL"
334 void SearchNextSpecial(sal_Bool _bSearchForNull
);
335 /// das naechste Vorkommen suchen, abhaengig von nDirection wird dabei am Anfang oder am Ende neu begonnen
336 void StartOver(const ::rtl::OUString
& strExpression
);
337 /// analogous, search for "NULL" (_bSearchForNull==sal_True) or "not NULL"
338 void StartOverSpecial(sal_Bool _bSearchForNull
);
339 /// die Angaben ueber letzte Fundstelle invalidieren
340 void InvalidatePreviousLoc();
342 /** baut m_arrUsedFields neu auf (nFieldIndex==-1 bedeutet alle Felder, ansonsten gibt es den Feldindex an)
343 wenn bForce nicht gesetzt ist, passiert bei nFieldIndex == m_nCurrentFieldIndex nichts
344 (ruft InvalidatePreviousLoc auf)
346 void RebuildUsedFields(sal_Int32 nFieldIndex
, sal_Bool bForce
= sal_False
);
347 ::rtl::OUString
FormatField(sal_Int32 nWhich
);
349 /// kehrt sofort zurueck; nachdem wirklich abgebrochen wurde, wird der ProgressHandler mit STATE_CANCELED aufgerufen
352 /** nur gueltig, wenn nicht gerade eine (asynchrone) Suche laeuft, die naechste Suche wird dann auf dem neuen Iterator
353 mit den neuen Parametern durchgefuehrt
355 sal_Bool
SwitchToContext(const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XResultSet
>& xCursor
, const ::rtl::OUString
& strVisibleFields
, const InterfaceArray
& arrFields
,
356 sal_Int32 nFieldIndex
);
359 void Init(const ::rtl::OUString
& strVisibleFields
);
361 void SearchNextImpl();
362 // diese Impl-Methode laeuft im SearchThread
364 // start a thread-search (or call SearchNextImpl directly, depending on the search mode)
365 void ImplStartNextSearch();
368 SVX_DLLPRIVATE
void clearControlTexts();
369 SVX_DLLPRIVATE
void fillControlTexts(const InterfaceArray
& arrFields
);
371 // three methods implementing a complete search loop (null/not null, wildcard, SearchText)
372 // (they all have some code in common, but with this solution we have do do a distinction only once per search (before
373 // starting the loop), not in every loop step
374 SVX_DLLPRIVATE SEARCH_RESULT
SearchSpecial(sal_Bool _bSearchForNull
, sal_Int32
& nFieldPos
, FieldCollectionIterator
& iterFieldLoop
,
375 const FieldCollectionIterator
& iterBegin
, const FieldCollectionIterator
& iterEnd
);
376 SVX_DLLPRIVATE SEARCH_RESULT
SearchWildcard(const ::rtl::OUString
& strExpression
, sal_Int32
& nFieldPos
, FieldCollectionIterator
& iterFieldLoop
,
377 const FieldCollectionIterator
& iterBegin
, const FieldCollectionIterator
& iterEnd
);
378 SVX_DLLPRIVATE SEARCH_RESULT
SearchRegularApprox(const ::rtl::OUString
& strExpression
, sal_Int32
& nFieldPos
, FieldCollectionIterator
& iterFieldLoop
,
379 const FieldCollectionIterator
& iterBegin
, const FieldCollectionIterator
& iterEnd
);
381 SVX_DLLPRIVATE
void PropagateProgress(sal_Bool _bDontPropagateOverflow
);
382 // ruft den ProgressHandler mit STATE_PROGRESS und der aktuellen Position des SearchIterators auf
384 // helpers, die ich mehrmals brauche
385 SVX_DLLPRIVATE sal_Bool
MoveCursor();
386 // bewegt m_xSearchIterator unter Beachtung von Richtung/Ueberlauf Cursor
387 SVX_DLLPRIVATE sal_Bool
MoveField(sal_Int32
& nPos
, FieldCollectionIterator
& iter
, const FieldCollectionIterator
& iterBegin
, const FieldCollectionIterator
& iterEnd
);
388 // bewegt den Iterator unter Beachtung von Richtung/Ueberlauf Iterator/Ueberlauf Cursor
389 SVX_DLLPRIVATE
void BuildAndInsertFieldInfo(const ::com::sun::star::uno::Reference
< ::com::sun::star::container::XIndexAccess
>& xAllFields
, sal_Int32 nField
);
390 // baut eine FieldInfo zum Feld Nummer nField (in xAllFields) auf und fuegt sie zu m_arrUsedFields hinzu
391 // xAllFields muss den DatabaseRecord-Service unterstuetzen
392 SVX_DLLPRIVATE ::rtl::OUString
FormatField(const FieldInfo
& rField
);
393 // formatiert das Feld mit dem NumberFormatter
395 SVX_DLLPRIVATE sal_Bool
HasPreviousLoc() { return m_aPreviousLocBookmark
.hasValue(); }
397 DECL_LINK(OnSearchTerminated
, FmSearchThread
*);
398 // wird vom SuchThread benutzt, nach Rueckkehr aus diesem Handler loescht sich der Thread selber
399 DECL_LINK(OnNewRecordCount
, void*);
402 #endif // _FMSRCIMP_HXX