Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sd/inc/Outliner.hxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#pragma once
21
22
#include <svx/svdoutl.hxx>
23
#include "pres.hxx"
24
#include "OutlinerIterator.hxx"
25
#include <editeng/SpellPortions.hxx>
26
#include <memory>
27
#include <utility>
28
29
class SdrObject;
30
class SdrTextObj;
31
class SdDrawDocument;
32
33
namespace weld
34
{
35
class Window;
36
}
37
38
namespace sd
39
{
40
class View;
41
class ViewShell;
42
class Window;
43
44
/// Describes a single search hit: a set of rectangles on a given page.
45
struct SearchSelection
46
{
47
    /// 0-based index of the page that has the selection.
48
    int m_nPage;
49
50
    /**
51
     * List of selection rectangles in twips -- multiple rectangles only in
52
     * case the selection spans over more layout lines.
53
     */
54
    OString m_aRectangles;
55
56
    SearchSelection(int nPage, OString aRectangles)
57
0
        : m_nPage(nPage)
58
0
        , m_aRectangles(std::move(aRectangles))
59
0
    {
60
0
    }
61
62
    bool operator==(const SearchSelection& rOther) const
63
0
    {
64
0
        return m_nPage == rOther.m_nPage && m_aRectangles == rOther.m_aRectangles;
65
0
    }
66
};
67
68
} // end of namespace sd
69
70
/** The main purpose of this class is searching and replacing as well as
71
    spelling of impress documents.  The main part of both tasks lies in
72
    iterating over the pages and view modes of a document and apply the
73
    respective function to all objects containing text on those pages.
74
75
    <p>Relevant objects: There are two sets of objects to search/spell
76
    check.  One is the set of all selected objects.  The other consists of
77
    all objects on all pages in draw-, notes-, and handout view as well as
78
    slide- and background view (draw pages and master pages).</p>
79
80
    <p>Iteration: Search/replace and spelling functions operate on shapes
81
    containing text.  To cover all relevant objects an order has to be
82
    defined on the objects.  For the set of all selected objects this order
83
    is simply the order in which they can be retrieved from the selection
84
    object.<br>
85
    When there is no selection the order is nested.  The three modes of the
86
    draw view are on the outer level: draw mode, notes mode, handout mode.
87
    The inner level switches between draw pages and master pages.  This
88
    leads to the following order:
89
    <ol>
90
    <li>draw pages of draw mode</li>
91
    <li>master pages of draw mode</li>
92
    <li>draw pages of notes mode</li>
93
    <li>master pages of notes mode</li>
94
    <li>draw pages of handout mode</li>
95
    <li>master pages of handout mode</li>
96
    </ol>
97
    Iteration starts at the top of the current page.  When reaching the end
98
    of the document, i.e. the last master page of the handout mode, it jumps
99
    to the first draw page of draw mode.  In backward searches this order is
100
    reversed.  When doing a <em>replace all</em> then the whole document is
101
    searched for matches starting at the first page of the draw/slide view
102
    (or last page of handout/background view even though search
103
    direction).</p>
104
105
    <p>The start position is restored after finishing spell checking or
106
    replacing all matches in a document.</p>
107
108
    <p>Some related pieces of information:
109
    The search dialog (<type>SvxSearchDialog</type>) can be controlled in
110
    more than one way:
111
    <ul><li>A set of option flags returned by the slot call
112
    SID_SEARCH_OPTIONS handled by the
113
    <member>SdDrawDocument::GetState()</member> method.</li>
114
    <li>The contents of the search item of type
115
    <type>SvxSearchItem</type>.</li>
116
    <li>The <member>HasSelection()</member> view shell method that returns
117
    whether or not a selection exists.  However, it is called from the
118
    search dialog with an argument so that only text selections are
119
    queried.  This is only sufficient for searching the outline view.
120
    </p>
121
*/
122
class SdOutliner final : public SdrOutliner
123
{
124
public:
125
    friend class ::sd::outliner::OutlinerContainer;
126
127
    /** Create a new sd outliner object.
128
        @param rDoc
129
            The draw document from which to take the content.
130
        @param nMode
131
            The valid values <const>OutlinerMode::DontKnow</const>,
132
            <const>OutlinerMode::TextObject</const>,
133
            <const>OutlinerMode::TitleObject</const>,
134
            <const>OutlinerMode::OutlineObject</const>, and
135
            <const>OutlinerMode::OutlineView</const> are defined in
136
            editeng/outliner.hxx.
137
    */
138
    SdOutliner(SdDrawDocument& rDoc, OutlinerMode nMode);
139
    virtual ~SdOutliner() override;
140
    /// Forbid copy construction and copy assignment
141
    SdOutliner(const Outliner&) = delete;
142
    SdOutliner& operator=(const Outliner&) = delete;
143
144
    /** Despite the name this method is called prior to spell checking *and*
145
        searching and replacing.  The position of current view
146
        mode/page/object/caret position is remembered and, depending on the
147
        search mode, may be restored after finishing searching/spell
148
        checking.
149
    */
150
    void PrepareSpelling();
151
152
    /** Initialize a spell check but do not start it yet.  This method
153
        is a better candidate for the name PrepareSpelling.
154
    */
155
    void StartSpelling();
156
157
    /** Initiate a find and/or replace on the next relevant text object.
158
        @return
159
            Returns </sal_True> when the search/replace is finished (as
160
            indicated by user input to the search dialog).  A </sal_False> value
161
            indicates that another call to this method is required.
162
    */
163
    bool StartSearchAndReplace(const SvxSearchItem* pSearchItem);
164
165
    /** Iterate over the sentences in all text shapes and stop at the
166
        next sentence with spelling errors. While doing so the view
167
        mode may be changed and text shapes are set into edit mode.
168
    */
169
    svx::SpellPortions GetNextSpellSentence();
170
171
    /** Release all resources that have been created during the find&replace
172
        or spell check.
173
    */
174
    void EndSpelling();
175
176
    /** callback for textconversion */
177
    bool ConvertNextDocument() override;
178
179
    /** Starts the text conversion (hangul/hanja or Chinese simplified/traditional)
180
    for the current viewshell */
181
    void StartConversion(LanguageType nSourceLanguage, LanguageType nTargetLanguage,
182
                         const vcl::Font* pTargetFont, sal_Int32 nOptions, bool bIsInteractive);
183
184
    /** This is called internally when text conversion is started.
185
        The position of current view mode/page/object/caret position
186
        is remembered and will be restored after conversion.
187
    */
188
    void BeginConversion();
189
190
    /** Release all resources that have been created during the conversion */
191
    void EndConversion();
192
193
0
    int GetIgnoreCurrentPageChangesLevel() const { return mnIgnoreCurrentPageChangesLevel; };
194
0
    void IncreIgnoreCurrentPageChangesLevel() { mnIgnoreCurrentPageChangesLevel++; };
195
0
    void DecreIgnoreCurrentPageChangesLevel() { mnIgnoreCurrentPageChangesLevel--; };
196
0
    SdDrawDocument& GetDoc() const { return mrDrawDocument; }
197
198
private:
199
    class Implementation;
200
    ::std::unique_ptr<Implementation> mpImpl;
201
202
    /// Returns the current outline view
203
    OutlinerView* getOutlinerView();
204
205
    /// Specifies whether to search and replace, to spell check or to do a
206
    /// text conversion.
207
    enum mode
208
    {
209
        SEARCH,
210
        SPELL,
211
        TEXT_CONVERSION
212
    } meMode;
213
214
    /// The view which displays the searched objects.
215
    ::sd::View* mpView;
216
    /** The view shell containing the view.  It is held as weak
217
        pointer to avoid keeping it alive when the view is changed
218
        during searching.
219
    */
220
    std::weak_ptr<::sd::ViewShell> mpWeakViewShell;
221
    /// This window contains the view.
222
    VclPtr<::sd::Window> mpWindow;
223
    /// The document on whose objects and pages this class operates.
224
    SdDrawDocument& mrDrawDocument;
225
226
    /** this is the language that is used for current text conversion.
227
        Only valid if meMode is TEXT_CONVERSION.
228
    */
229
    LanguageType mnConversionLanguage;
230
231
    /** While the value of this flag is greater than 0 changes of the current page
232
        do not lead to selecting the corresponding text in the outliner.
233
    */
234
    int mnIgnoreCurrentPageChangesLevel;
235
236
    /// Specifies whether the search string has been found so far.
237
    bool mbStringFound;
238
239
    /** This flag indicates whether there may exist a match of the search
240
        string before/after the current position in the document.  It can be
241
        set to </sal_False> only when starting from the beginning/end of the
242
        document.  When reaching the end/beginning with it still be set to
243
        </sal_False> then there exists no match and the search can be terminated.
244
    */
245
    bool mbMatchMayExist;
246
247
    /// The number of pages in the current view.
248
    sal_uInt16 mnPageCount;
249
250
    /** A <TRUE/> value indicates that the end of the find&replace or spell
251
        check has been reached.
252
    */
253
    bool mbEndOfSearch;
254
255
    /** Set to <TRUE/> when an object has been prepared successfully for
256
        searching/spell checking.  This flag directs the internal iteration
257
        which stops when set to </sal_True>.
258
    */
259
    bool mbFoundObject;
260
261
    /** This flag indicates whether to search forward or backwards.
262
    */
263
    bool mbDirectionIsForward;
264
265
    /** This flag indicates that only the selected objects are to be
266
        searched.
267
    */
268
    bool mbRestrictSearchToSelection;
269
270
    /** When the search is restricted to the current selection then
271
        this list contains pointers to all the objects of the
272
        selection.  This copy is necessary because during the search
273
        process the mark list is modified.
274
    */
275
    ::std::vector<unotools::WeakReference<SdrObject>> maMarkListCopy;
276
277
    /** Current object that may be a text object.  The object pointer to
278
        corresponds to <member>mnObjIndex</member>.  While iterating over the
279
        objects on a page <member>mpObj</member> will point to every object
280
        while <member>mpTextObj</member> will be set only to valid text
281
        objects.
282
    */
283
    SdrObject* mpObj;
284
285
    /** this stores the first object that is used for text conversion.
286
        Conversion automatically wraps around the document and stops when it
287
        finds this object again.
288
    */
289
    SdrObject* mpFirstObj;
290
291
    /// Candidate for being searched/spell checked.
292
    SdrTextObj* mpSearchSpellTextObj;
293
294
    /// Current text to be searched/spelled inside the current text object
295
    sal_Int32 mnText;
296
297
    /// Paragraph object of <member>mpTextObj</member>.
298
    OutlinerParaObject* mpParaObj;
299
300
    /// The view mode that was active when starting to search/spell check.
301
    PageKind meStartViewMode;
302
303
    /// The master page mode that was active when starting to search/spell check.
304
    EditMode meStartEditMode;
305
306
    /// The current page index on starting to search/spell check.
307
    sal_uInt16 mnStartPageIndex;
308
309
    /// The object in edit mode when searching /spell checking was started
310
    /// (if any).
311
    SdrObject* mpStartEditedObject;
312
313
    /// The position of the caret when searching /spell checking was started.
314
    ESelection maStartSelection;
315
316
    /** The search item contains various attributes that define the type of
317
        search.  It is set every time the
318
        <member>SearchAndReplaceAll</member> method is called.
319
    */
320
    std::unique_ptr<const SvxSearchItem> mpSearchItem;
321
322
    /// The actual object iterator.
323
    ::sd::outliner::Iterator maObjectIterator;
324
    /// The current position of the object iterator.
325
    ::sd::outliner::IteratorPosition maCurrentPosition;
326
    /// The position when the search started.  Corresponds largely to the
327
    /// m?Start* members.
328
    ::sd::outliner::Iterator maSearchStartPosition;
329
    /** The last valid position describes where the last text object has been
330
        found.  This position is restored when some dialogs are shown.  The
331
        position is initially set to the where the search begins.
332
    */
333
    ::sd::outliner::IteratorPosition maLastValidPosition;
334
335
    /** When this flag is true then a PrepareSpelling() is executed when
336
        StartSearchAndReplace() is called the next time.
337
    */
338
    bool mbPrepareSpellingPending;
339
340
    /** Initialize the object iterator.  Call this method after being
341
        invoked from the search or spellcheck dialog.  It creates a new
342
        iterator pointing at the current object when this has not been done
343
        before.  It reverses the direction of iteration if the given flag
344
        differs from the current direction.
345
        @param bDirectionIsForward
346
            This flag specifies in which direction to iterator over the
347
            objects.  If it differs from the current direction the iterator
348
            is reversed.
349
    */
350
    void Initialize(bool bDirectionIsForward);
351
352
    /** Do search and replace for whole document.
353
    */
354
    bool SearchAndReplaceAll();
355
356
    /** Do search and replace for next match.
357
        @param pSelections
358
            When tiled rendering and not 0, then don't emit LOK events, instead
359
            assume the caller will do so.
360
        @return
361
            The return value specifies whether the search ended (</sal_True>) or
362
            another call to this method is required (</sal_False>).
363
    */
364
    bool SearchAndReplaceOnce(std::vector<::sd::SearchSelection>* pSelections = nullptr);
365
366
    void sendLOKSearchResultCallback(const std::shared_ptr<sd::ViewShell>& pViewShell,
367
                                     const OutlinerView* pOutlinerView,
368
                                     std::vector<sd::SearchSelection>* pSelections);
369
370
    /** Detect changes of the document or view and react accordingly.  Such
371
        changes may occur because different calls to
372
        <member>SearchAndReplace()</member> there usually is user
373
        interaction.  This is at least the press of the search or replace
374
        button but may include any other action some of which affect the
375
        search.
376
    */
377
    void DetectChange();
378
379
    /** Detect whether the selection has changed.
380
        @return
381
            Return <TRUE/> when the selection has been changed since the
382
            last call to this method.
383
    */
384
    bool DetectSelectionChange();
385
386
    /** Remember the current edited object/caret position/page/view mode
387
        when starting to search/spell check so that it can be restored on
388
        termination.
389
    */
390
    void RememberStartPosition();
391
392
    /** Restore the position stored in the last call of
393
        <member>RememberStartPositiony</member>.
394
    */
395
    void RestoreStartPosition();
396
397
    /** Provide next object to search or spell check as text object in edit
398
        mode on the current page.  This skips all objects that do not
399
        match or are no text object.
400
    */
401
    void ProvideNextTextObject();
402
403
    /** Handle the situation that the iterator has reached the last object.
404
        This may result in setting the <member>mbEndOfSearch</member> flag
405
        back to </sal_False>.  This method may show either the end-of-search
406
        dialog or the wrap-around dialog.
407
    */
408
    void EndOfSearch();
409
410
    /** Show a dialog that tells the user that the search has ended either
411
        because there are no more matches after finding at least one or that
412
        no match has been found at all.
413
    */
414
    void ShowEndOfSearchDialog();
415
416
    /** Show a dialog that asks the user whether to wrap around to the
417
        beginning/end of the document and continue with the search/spell
418
        check.
419
    */
420
    bool ShowWrapAroundDialog();
421
422
    /** Put text of current text object into outliner so that the text can
423
        be searched/spell checked.
424
    */
425
    void PutTextIntoOutliner();
426
427
    /** Prepare to do spell checking on the current text object.  This
428
        includes putting it into edit mode.  Under certain conditions this
429
        method sets <member>mbEndOfSearch</member> to <TRUE/>.
430
    */
431
    void PrepareSpellCheck();
432
433
    /** Prepare to search and replace on the current text object.  This
434
        includes putting it into edit mode.
435
    */
436
    void PrepareSearchAndReplace();
437
438
    /** Prepare to do a text conversion on the current text
439
        object. This includes putting it into edit mode.
440
    */
441
    void PrepareConversion();
442
443
    /** Switch to a new view mode.  Try to restore the original edit mode
444
        before doing so.
445
        @param ePageKind
446
            Specifies the new view mode.
447
    */
448
    void SetViewMode(PageKind ePageKind);
449
450
    /** Switch to the page or master page specified by the
451
        <member>mnPage</member> index.  Master page mode is specified by
452
        <member>meEditMode</member>.
453
        @param eEditMode
454
            The new edit mode.
455
        @param nPageIndex
456
            The new page index.
457
    */
458
    void SetPage(EditMode eEditMode, sal_uInt16 nPageIndex);
459
460
    /** Switch on edit mode for the currently selected text object.
461
    */
462
    void EnterEditMode(bool bGrabFocus);
463
464
    /** Return the position at which a new search is started with respect to
465
        the search direction as specified by the argument.
466
        @return
467
            The position mentioned above in form of a selection with start
468
            equals end.
469
    */
470
    ESelection GetSearchStartPosition() const;
471
472
    /** Detect whether there exists a previous match.  Note that only the
473
        absence of such a match can be detected reliably.  An existing match
474
        is assumed when the search started not at the beginning/end of the
475
        presentation.  This does not have to be true.  The user can have set
476
        the cursor at the middle of the text without a prior search.
477
        @return
478
            Returns </True> when there is no previous match and </False>
479
            when there may be one.
480
    */
481
    bool HasNoPreviousMatch();
482
483
    /** Handle a failed search (with or without replace) for the outline
484
        mode.  Show message boxes when the search failed completely,
485
        i.e. there is no match in the whole presentation, or when no further
486
        match exists.
487
        @return
488
            The returned value indicates whether another (wrapped around)
489
            search shall take place.  If that is so, then it is the caller's
490
            responsibility to set the cursor position accordingly.
491
    */
492
    bool HandleFailedSearch();
493
494
    /** Take a position as returned by an object iterator and switch to the
495
        view and page on which the object specified by this position is
496
        located.
497
        @param rPosition
498
            This position points to a <type>SdrObject</type> object and
499
            contains the view and page where it is located.
500
        @return
501
            Return a pointer to the <type>SdrObject</type>.
502
    */
503
    SdrObject* SetObject(const ::sd::outliner::IteratorPosition& rPosition);
504
505
    /** Use this method when the view shell in which to search has changed.
506
        It handles i.e. registering at the associated view as selection
507
        change listener.
508
    */
509
    void SetViewShell(const std::shared_ptr<::sd::ViewShell>& rpViewShell);
510
511
    /** Activate or deactivate the search in the current selection.  Call
512
        this method whenever the selection has changed.  This method creates
513
        a copy of the current selection and reassigns the object iterator to
514
        the current() iterator.
515
    */
516
    void HandleChangedSelection();
517
518
    /** Initiate the spell check of the next relevant text object.
519
        When the outline view is active then this method is called
520
        after a wrap around to continue at the beginning of the document.
521
        @return
522
            Returns <TRUE/> to indicate that another call to this method is
523
            required.  When all text objects have been processed then
524
            <FALSE/> is returned.
525
    */
526
    virtual bool SpellNextDocument() override;
527
528
    /** Find the right parent to use for a message. This function makes sure
529
        that the otherwise non-modal search or spell dialogs, if visible, are
530
        locked, too.
531
    */
532
    weld::Window* GetMessageBoxParent();
533
};
534
535
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */