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 _FMSRCIMP_HXX 25 #define _FMSRCIMP_HXX 26 27 #include <svx/fmtools.hxx> 28 #include "svx/svxdllapi.h" 29 30 /** === begin UNO includes === **/ 31 #include <com/sun/star/awt/XCheckBox.hpp> 32 #include <com/sun/star/awt/XListBox.hpp> 33 #include <com/sun/star/awt/XTextComponent.hpp> 34 #include <com/sun/star/util/XNumberFormatsSupplier.hpp> 35 #include <com/sun/star/util/XNumberFormatter.hpp> 36 /** === end UNO includes === **/ 37 38 #include <comphelper/stl_types.hxx> 39 #include <cppuhelper/implbase1.hxx> 40 #include <osl/mutex.hxx> 41 #include <unotools/charclass.hxx> 42 #include <unotools/collatorwrapper.hxx> 43 #include <vos/thread.hxx> 44 45 #include <deque> 46 47 // =================================================================================================== 48 // = class FmSearchThread - wie der Name schon sagt 49 // =================================================================================================== 50 51 class FmSearchEngine; 52 class FmSearchThread : public ::vos::OThread 53 { 54 FmSearchEngine* m_pEngine; 55 Link m_aTerminationHdl; 56 57 virtual void SAL_CALL run(); 58 virtual void SAL_CALL onTerminated(); 59 60 public: FmSearchThread(FmSearchEngine * pEngine)61 FmSearchThread(FmSearchEngine* pEngine) : m_pEngine(pEngine) { } setTerminationHandler(Link aHdl)62 void setTerminationHandler(Link aHdl) { m_aTerminationHdl = aHdl; } 63 }; 64 65 // =================================================================================================== 66 // = struct FmSearchProgress - diese Struktur bekommt der Owner der SearchEngine fuer Status-Updates 67 // = (und am Ende der Suche) 68 // =================================================================================================== 69 70 struct FmSearchProgress 71 { 72 enum STATE { STATE_PROGRESS, STATE_PROGRESS_COUNTING, STATE_CANCELED, STATE_SUCCESSFULL, STATE_NOTHINGFOUND, STATE_ERROR }; 73 // (Bewegung auf neuen Datensatz; Fortschritt beim Zaehlen von Datensaetzen; abgebrochen; Datensatz gefunden; 74 // nichts gefunden, irgendein nicht zu handelnder Fehler) 75 STATE aSearchState; 76 77 // aktueller Datensatz - immer gueltig (ist zum Beispiel bei Abbrechen auch fuer das Weitersuchen interesant) 78 sal_uInt32 nCurrentRecord; 79 // Ueberlauf - nur gueltig bei STATE_PROGRESS 80 sal_Bool bOverflow; 81 82 // die Position des Such-Cursors - bei STATE_SUCCESSFULL, STATE_CANCELED und STATE_NOTHING_FOUND gueltig 83 ::com::sun::star::uno::Any aBookmark; 84 // das Feld, in dem der Text gefunden wurde - bei STATE_SUCCESSFULL gueltig 85 sal_Int32 nFieldIndex; 86 }; 87 88 // =================================================================================================== 89 // = class FmRecordCountListener - Hilfsklasse fuer FmSearchEngine, lauscht an einem Cursor und teilt 90 // = Aenderungem im RecordCount mit 91 // =================================================================================================== 92 93 class FmRecordCountListener : public ::cppu::WeakImplHelper1< ::com::sun::star::beans::XPropertyChangeListener> 94 { 95 // Atribute 96 Link m_lnkWhoWantsToKnow; 97 ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > m_xListening; 98 99 // Attribut-Zugriff 100 public: 101 Link SetPropChangeHandler(const Link& lnk); 102 103 // Oprationen 104 public: 105 FmRecordCountListener(const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet >& dbcCursor); 106 // the set has to support the sdb::ResultSet service 107 virtual ~FmRecordCountListener(); 108 109 // DECLARE_UNO3_AGG_DEFAULTS(FmPropertyListener, UsrObject); 110 // virtual sal_Bool queryInterface(::com::sun::star::uno::Uik aUik, ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rOut); 111 112 // ::com::sun::star::lang::XEventListener 113 virtual void SAL_CALL disposing(const ::com::sun::star::lang::EventObject& Source) throw(::com::sun::star::uno::RuntimeException); 114 115 // ::com::sun::star::beans::XPropertyChangeListener 116 virtual void SAL_CALL propertyChange(const ::com::sun::star::beans::PropertyChangeEvent& evt) throw(::com::sun::star::uno::RuntimeException); 117 118 void DisConnect(); 119 120 private: 121 void NotifyCurrentCount(); 122 123 }; 124 125 // =================================================================================================== 126 // = class FmSearchEngine - Impl-Klasse fuer FmSearchDialog 127 // =================================================================================================== 128 129 namespace svxform { 130 // 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. 131 // While searching we don't want to do this distinction for every control in every round. So we need some helpers. 132 class ControlTextWrapper 133 { 134 // attributes 135 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xControl; 136 // attribute access 137 public: getControl() const138 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > getControl() const{ return m_xControl; } 139 public: ControlTextWrapper(const::com::sun::star::uno::Reference<::com::sun::star::uno::XInterface> & _xControl)140 ControlTextWrapper(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _xControl) { m_xControl = _xControl; } ~ControlTextWrapper()141 virtual ~ControlTextWrapper() { } 142 143 virtual ::rtl::OUString getCurrentText() const = 0; 144 }; 145 class SimpleTextWrapper : public ControlTextWrapper 146 { 147 ::com::sun::star::uno::Reference< ::com::sun::star::awt::XTextComponent > m_xText; 148 public: 149 SimpleTextWrapper(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XTextComponent >& _xText); 150 virtual ::rtl::OUString getCurrentText() const; 151 }; 152 class ListBoxWrapper : public ControlTextWrapper 153 { 154 ::com::sun::star::uno::Reference< ::com::sun::star::awt::XListBox > m_xBox; 155 public: 156 ListBoxWrapper(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XListBox >& _xBox); 157 virtual ::rtl::OUString getCurrentText() const; 158 }; 159 class CheckBoxWrapper : public ControlTextWrapper 160 { 161 ::com::sun::star::uno::Reference< ::com::sun::star::awt::XCheckBox > m_xBox; 162 public: 163 CheckBoxWrapper(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XCheckBox >& _xBox); 164 virtual ::rtl::OUString getCurrentText() const; 165 }; 166 } 167 168 enum FMSEARCH_MODE { SM_BRUTE, SM_ALLOWSCHEDULE, SM_USETHREAD }; 169 170 DECLARE_STL_VECTOR( ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>, InterfaceArray); 171 172 class SVX_DLLPUBLIC FmSearchEngine 173 { 174 friend class FmSearchThread; 175 176 enum SEARCH_RESULT { SR_FOUND, SR_NOTFOUND, SR_ERROR, SR_CANCELED }; 177 enum SEARCHFOR_TYPE { SEARCHFOR_STRING, SEARCHFOR_NULL, SEARCHFOR_NOTNULL }; 178 179 // zugrundeliegende Daten 180 CursorWrapper m_xSearchCursor; 181 std::deque<sal_Int32> m_arrFieldMapping; 182 // da der Iterator durchaus mehr Spalten haben kann, als ich eigentlich verwalte (in meiner Feld-Listbox), 183 // muss ich mir hier ein Mapping dieser ::com::sun::star::form-Schluessel auf die Indizies der entsprechenden Spalten im Iterator halten 184 185 // der Formatter 186 ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier > m_xFormatSupplier; 187 ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter > m_xFormatter; 188 189 CharClass m_aCharacterClassficator; 190 CollatorWrapper m_aStringCompare; 191 192 // die Sammlung aller interesanten Felder (bzw. ihre ::com::sun::star::data::XDatabaseVariant-Interfaces und ihre FormatKeys) 193 struct FieldInfo 194 { 195 ::com::sun::star::uno::Reference< ::com::sun::star::sdb::XColumn > xContents; 196 sal_uInt32 nFormatKey; 197 sal_Bool bDoubleHandling; 198 }; 199 200 DECLARE_STL_VECTOR(FieldInfo, FieldCollection); 201 FieldCollection m_arrUsedFields; 202 sal_Int32 m_nCurrentFieldIndex; // der letzte Parameter von RebuildUsedFields, ermoeglicht mir Checks in FormatField 203 204 DECLARE_STL_VECTOR(svxform::ControlTextWrapper*, ControlTextSuppliers); 205 ControlTextSuppliers m_aControlTexts; 206 207 sal_Bool m_bUsingTextComponents; 208 CursorWrapper m_xOriginalIterator; 209 CursorWrapper m_xClonedIterator; 210 211 // Daten fuer Entscheidung, in welchem Feld ich ein "Found" akzeptiere 212 ::com::sun::star::uno::Any m_aPreviousLocBookmark; // Position, an der ich zuletzt fuendig war 213 FieldCollectionIterator m_iterPreviousLocField; // dito Feld 214 215 // Kommunikation mit dem Thread, der die eigentliche Suche durchfuehrt 216 ::rtl::OUString m_strSearchExpression; // Hinrichtung 217 SEARCHFOR_TYPE m_eSearchForType; // dito 218 SEARCH_RESULT m_srResult; // Rueckrichtung 219 220 // der Link, dem ich Fortschritte und Ergebnisse mitteile 221 Link m_aProgressHandler; 222 sal_Bool m_bSearchingCurrently : 1; // laeuft gerade eine (asynchrone) Suche ? 223 sal_Bool m_bCancelAsynchRequest : 1; // soll abgebrochen werden ? 224 ::osl::Mutex m_aCancelAsynchAccess; // Zugriff auf m_bCancelAsynchRequest (eigentlich nur bei 225 // m_eMode == SM_USETHREAD interesant) 226 FMSEARCH_MODE m_eMode; //CHINA001 FmSearchDialog::SEARCH_MODE m_eMode; // der aktuelle Modus 227 // der aktuelle Modus 228 229 // Parameter fuer die Suche 230 sal_Bool m_bFormatter : 1; // Feldformatierung benutzen 231 sal_Bool m_bForward : 1; // Richtung 232 sal_Bool m_bWildcard : 1; // Platzhalter-Suche ? 233 sal_Bool m_bRegular : 1; // regulaerer Ausdruck 234 sal_Bool m_bLevenshtein : 1; // Levenshtein-Suche 235 sal_Bool m_bTransliteration : 1; // Levenshtein-Suche 236 237 sal_Bool m_bLevRelaxed : 1; // Parameter fuer Levenshtein-Suche 238 sal_uInt16 m_nLevOther; 239 sal_uInt16 m_nLevShorter; 240 sal_uInt16 m_nLevLonger; 241 242 sal_uInt16 m_nPosition; // wenn nicht regulaer oder lev, dann einer der MATCHING_...-Werte 243 244 sal_Int32 m_nTransliterationFlags; 245 246 // ------------- 247 // Memberzugriff 248 private: 249 SVX_DLLPRIVATE sal_Bool CancelRequested(); // liefert eine durch m_aCancelAsynchAccess gesicherte Auswertung von m_bCancelAsynchRequest 250 251 public: 252 void SetCaseSensitive(sal_Bool bSet); 253 sal_Bool GetCaseSensitive() const; 254 255 void SetFormatterUsing(sal_Bool bSet); // das ist etwas umfangreicher, deshalb kein hier inline .... GetFormatterUsing() const256 sal_Bool GetFormatterUsing() const { return m_bFormatter; } 257 SetDirection(sal_Bool bForward)258 void SetDirection(sal_Bool bForward) { m_bForward = bForward; } GetDirection() const259 sal_Bool GetDirection() const { return m_bForward; } 260 SetWildcard(sal_Bool bSet)261 void SetWildcard(sal_Bool bSet) { m_bWildcard = bSet; } GetWildcard() const262 sal_Bool GetWildcard() const { return m_bWildcard; } 263 SetRegular(sal_Bool bSet)264 void SetRegular(sal_Bool bSet) { m_bRegular = bSet; } GetRegular() const265 sal_Bool GetRegular() const { return m_bRegular; } 266 SetLevenshtein(sal_Bool bSet)267 void SetLevenshtein(sal_Bool bSet) { m_bLevenshtein = bSet; } GetLevenshtein() const268 sal_Bool GetLevenshtein() const { return m_bLevenshtein; } 269 270 void SetIgnoreWidthCJK(sal_Bool bSet); 271 sal_Bool GetIgnoreWidthCJK() const; 272 SetTransliteration(sal_Bool bSet)273 void SetTransliteration(sal_Bool bSet) { m_bTransliteration = bSet; } GetTransliteration() const274 sal_Bool GetTransliteration() const { return m_bTransliteration; } 275 SetLevRelaxed(sal_Bool bSet)276 void SetLevRelaxed(sal_Bool bSet) { m_bLevRelaxed = bSet; } GetLevRelaxed() const277 sal_Bool GetLevRelaxed() const { return m_bLevRelaxed; } SetLevOther(sal_uInt16 nHowMuch)278 void SetLevOther(sal_uInt16 nHowMuch) { m_nLevOther = nHowMuch; } GetLevOther() const279 sal_uInt16 GetLevOther() const { return m_nLevOther; } SetLevShorter(sal_uInt16 nHowMuch)280 void SetLevShorter(sal_uInt16 nHowMuch) { m_nLevShorter = nHowMuch; } GetLevShorter() const281 sal_uInt16 GetLevShorter() const { return m_nLevShorter; } SetLevLonger(sal_uInt16 nHowMuch)282 void SetLevLonger(sal_uInt16 nHowMuch) { m_nLevLonger = nHowMuch; } GetLevLonger() const283 sal_uInt16 GetLevLonger() const { return m_nLevLonger; } 284 // die ganzen Lev-Werte werden nur bei m_bLevenshtein==sal_True beachtet 285 SetTransliterationFlags(sal_Int32 _nFlags)286 void SetTransliterationFlags(sal_Int32 _nFlags) { m_nTransliterationFlags = _nFlags; } GetTransliterationFlags() const287 sal_Int32 GetTransliterationFlags() const { return m_nTransliterationFlags; } 288 SetPosition(sal_uInt16 nValue)289 void SetPosition(sal_uInt16 nValue) { m_nPosition = nValue; } GetPosition() const290 sal_uInt16 GetPosition() const { return m_nPosition; } 291 // Position wird bei m_bWildCard==sal_True nicht beachtet 292 GetSearchMode() const293 FMSEARCH_MODE GetSearchMode() const { return m_eMode; } 294 295 public: 296 /** zwei Constructoren, beide analog zu denen des FmSearchDialog, Erklaerung siehe also dort .... 297 xCursor muss jeweils den ::com::sun::star::data::DatabaseCursor-Service implementieren. 298 wenn eMode == SM_USETHREAD, sollte ein ProgressHandler gesetzt sein, da dann die Ergebnisuebermittlung ueber diesen 299 Handler erfolgt. 300 Ist eMode != SM_USETHREAD, kehren SearchNext und StarOver nicht zurueck, bevor die Suche (erfolgreich oder nicht) beendet 301 wurde, dann kann man das Ergebnis danach abfragen. Ist zusaetzlich der ProgressHandler gesetzt, wird dieser fuer jeden neuen 302 Datensatz sowie am Ende der Suche aufgerufen. 303 */ 304 FmSearchEngine( 305 const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxORB, 306 const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet >& xCursor, 307 const ::rtl::OUString& strVisibleFields, 308 const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier >& xFormat, 309 FMSEARCH_MODE eMode);//CHINA001 FmSearchDialog::SEARCH_MODE eMode); 310 FmSearchEngine( 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 InterfaceArray& arrFields, 315 FMSEARCH_MODE eMode); //CHINA001 FmSearchDialog::SEARCH_MODE eMode); 316 317 virtual ~FmSearchEngine(); 318 319 /** der Link wird fuer jeden Datensatz und nach Beendigung der Suche aufgerufen, Parameter ist ein Zeiger auf 320 eine FmSearchProgress-Struktur 321 der Handler sollte auf jeden Fall Thread-sicher sein 322 */ SetProgressHandler(Link aHdl)323 void SetProgressHandler(Link aHdl) { m_aProgressHandler = aHdl; } 324 325 /// das naechste Vorkommen suchen (Werte fuer nDirection siehe DIRECTION_*-defines) 326 void SearchNext(const ::rtl::OUString& strExpression); 327 /// analogous, search for "NULL" (_bSearchForNull==sal_True) or "not NULL" 328 void SearchNextSpecial(sal_Bool _bSearchForNull); 329 /// das naechste Vorkommen suchen, abhaengig von nDirection wird dabei am Anfang oder am Ende neu begonnen 330 void StartOver(const ::rtl::OUString& strExpression); 331 /// analogous, search for "NULL" (_bSearchForNull==sal_True) or "not NULL" 332 void StartOverSpecial(sal_Bool _bSearchForNull); 333 /// die Angaben ueber letzte Fundstelle invalidieren 334 void InvalidatePreviousLoc(); 335 336 /** baut m_arrUsedFields neu auf (nFieldIndex==-1 bedeutet alle Felder, ansonsten gibt es den Feldindex an) 337 wenn bForce nicht gesetzt ist, passiert bei nFieldIndex == m_nCurrentFieldIndex nichts 338 (ruft InvalidatePreviousLoc auf) 339 */ 340 void RebuildUsedFields(sal_Int32 nFieldIndex, sal_Bool bForce = sal_False); 341 ::rtl::OUString FormatField(sal_Int32 nWhich); 342 343 /// kehrt sofort zurueck; nachdem wirklich abgebrochen wurde, wird der ProgressHandler mit STATE_CANCELED aufgerufen 344 void CancelSearch(); 345 346 /** nur gueltig, wenn nicht gerade eine (asynchrone) Suche laeuft, die naechste Suche wird dann auf dem neuen Iterator 347 mit den neuen Parametern durchgefuehrt 348 */ 349 sal_Bool SwitchToContext(const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet >& xCursor, const ::rtl::OUString& strVisibleFields, const InterfaceArray& arrFields, 350 sal_Int32 nFieldIndex); 351 352 protected: 353 void Init(const ::rtl::OUString& strVisibleFields); 354 355 void SearchNextImpl(); 356 // diese Impl-Methode laeuft im SearchThread 357 358 // start a thread-search (or call SearchNextImpl directly, depending on the search mode) 359 void ImplStartNextSearch(); 360 361 private: 362 SVX_DLLPRIVATE void clearControlTexts(); 363 SVX_DLLPRIVATE void fillControlTexts(const InterfaceArray& arrFields); 364 365 // three methods implementing a complete search loop (null/not null, wildcard, SearchText) 366 // (they all have some code in common, but with this solution we have do do a distinction only once per search (before 367 // starting the loop), not in every loop step 368 SVX_DLLPRIVATE SEARCH_RESULT SearchSpecial(sal_Bool _bSearchForNull, sal_Int32& nFieldPos, FieldCollectionIterator& iterFieldLoop, 369 const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd); 370 SVX_DLLPRIVATE SEARCH_RESULT SearchWildcard(const ::rtl::OUString& strExpression, sal_Int32& nFieldPos, FieldCollectionIterator& iterFieldLoop, 371 const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd); 372 SVX_DLLPRIVATE SEARCH_RESULT SearchRegularApprox(const ::rtl::OUString& strExpression, sal_Int32& nFieldPos, FieldCollectionIterator& iterFieldLoop, 373 const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd); 374 375 SVX_DLLPRIVATE void PropagateProgress(sal_Bool _bDontPropagateOverflow); 376 // ruft den ProgressHandler mit STATE_PROGRESS und der aktuellen Position des SearchIterators auf 377 378 // helpers, die ich mehrmals brauche 379 SVX_DLLPRIVATE sal_Bool MoveCursor(); 380 // bewegt m_xSearchIterator unter Beachtung von Richtung/Ueberlauf Cursor 381 SVX_DLLPRIVATE sal_Bool MoveField(sal_Int32& nPos, FieldCollectionIterator& iter, const FieldCollectionIterator& iterBegin, const FieldCollectionIterator& iterEnd); 382 // bewegt den Iterator unter Beachtung von Richtung/Ueberlauf Iterator/Ueberlauf Cursor 383 SVX_DLLPRIVATE void BuildAndInsertFieldInfo(const ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexAccess >& xAllFields, sal_Int32 nField); 384 // baut eine FieldInfo zum Feld Nummer nField (in xAllFields) auf und fuegt sie zu m_arrUsedFields hinzu 385 // xAllFields muss den DatabaseRecord-Service unterstuetzen 386 SVX_DLLPRIVATE ::rtl::OUString FormatField(const FieldInfo& rField); 387 // formatiert das Feld mit dem NumberFormatter 388 HasPreviousLoc()389 SVX_DLLPRIVATE sal_Bool HasPreviousLoc() { return m_aPreviousLocBookmark.hasValue(); } 390 391 DECL_LINK(OnSearchTerminated, FmSearchThread*); 392 // wird vom SuchThread benutzt, nach Rueckkehr aus diesem Handler loescht sich der Thread selber 393 DECL_LINK(OnNewRecordCount, void*); 394 }; 395 396 #endif // _FMSRCIMP_HXX 397 398