Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/view/spelldialog.cxx
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
#include <spelldialog.hxx>
21
22
#include <sfx2/bindings.hxx>
23
#include <svx/svxids.hrc>
24
#include <editeng/editstat.hxx>
25
#include <editeng/editview.hxx>
26
#include <editeng/unolingu.hxx>
27
#include <selectionstate.hxx>
28
#include <osl/diagnose.h>
29
30
#include <spelleng.hxx>
31
#include <tabvwsh.hxx>
32
#include <docsh.hxx>
33
#include <scmod.hxx>
34
#include <editable.hxx>
35
#include <undoblk.hxx>
36
#include <gridwin.hxx>
37
#include <refupdatecontext.hxx>
38
#include <vcl/svapp.hxx>
39
40
SFX_IMPL_CHILDWINDOW_WITHID( ScSpellDialogChildWindow, SID_SPELL_DIALOG )
41
42
ScSpellDialogChildWindow::ScSpellDialogChildWindow( vcl::Window* pParentP, sal_uInt16 nId,
43
        SfxBindings* pBindings, SAL_UNUSED_PARAMETER SfxChildWinInfo* /*pInfo*/ ) :
44
0
    svx::SpellDialogChildWindow( pParentP, nId, pBindings ),
45
0
    mpViewShell( nullptr ),
46
0
    mpViewData( nullptr ),
47
0
    mpDocShell( nullptr ),
48
0
    mpDoc( nullptr ),
49
0
    mbNeedNextObj( false ),
50
0
    mbOldIdleEnabled(true)
51
0
{
52
0
    Init();
53
0
}
54
55
ScSpellDialogChildWindow::~ScSpellDialogChildWindow()
56
0
{
57
0
    Reset();
58
0
}
59
60
SfxChildWinInfo ScSpellDialogChildWindow::GetInfo() const
61
0
{
62
    // tdf#117020: visible gets written to UserData
63
    // and a value of true means it automatically opens on startup
64
0
    SfxChildWinInfo aInfo = svx::SpellDialogChildWindow::GetInfo();
65
0
    aInfo.bVisible = false;
66
0
    return aInfo;
67
0
}
68
69
void ScSpellDialogChildWindow::InvalidateSpellDialog()
70
0
{
71
0
    svx::SpellDialogChildWindow::InvalidateSpellDialog();
72
0
}
73
74
// protected ------------------------------------------------------------------
75
76
svx::SpellPortions ScSpellDialogChildWindow::GetNextWrongSentence( bool /*bRecheck*/ )
77
0
{
78
0
    svx::SpellPortions aPortions;
79
0
    if( mxEngine && mpViewData )
80
0
    {
81
0
        if( EditView* pEditView = mpViewData->GetSpellingView() )
82
0
        {
83
            // edit engine handles cell iteration internally
84
0
            do
85
0
            {
86
0
                if( mbNeedNextObj )
87
0
                    mxEngine->SpellNextDocument();
88
0
                mbNeedNextObj = !mxEngine->IsFinished() && !mxEngine->SpellSentence( *pEditView, aPortions );
89
0
            }
90
0
            while( mbNeedNextObj );
91
0
        }
92
0
    }
93
0
    return aPortions;
94
0
}
95
96
void ScSpellDialogChildWindow::ApplyChangedSentence( const svx::SpellPortions& rChanged, bool bRecheck )
97
0
{
98
0
    if( mxEngine && mpViewData )
99
0
        if( EditView* pEditView = mpViewData->GetSpellingView() )
100
0
        {
101
0
            mxEngine->ApplyChangedSentence( *pEditView, rChanged, bRecheck );
102
103
            // Reset the spell checking results to clear the markers.
104
0
            mpViewData->GetActiveWin()->ResetAutoSpell();
105
0
        }
106
0
}
107
108
void ScSpellDialogChildWindow::GetFocus(bool bForceResume)
109
0
{
110
0
    SolarMutexGuard aGuard;
111
112
0
    if (bForceResume || IsSelectionChanged())
113
0
    {
114
0
        Reset();
115
0
        InvalidateSpellDialog();
116
0
        Init();
117
0
    }
118
0
}
119
120
void ScSpellDialogChildWindow::LoseFocus()
121
0
{
122
0
}
123
124
// private --------------------------------------------------------------------
125
126
void ScSpellDialogChildWindow::Reset()
127
0
{
128
0
    if( mpViewShell && (mpViewShell == dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() ))  )
129
0
    {
130
0
        if( mxEngine && mxEngine->IsAnyModified() )
131
0
        {
132
0
            const ScAddress& rCursor = mxOldSel->GetCellCursor();
133
0
            SCTAB nTab = rCursor.Tab();
134
0
            SCCOL nOldCol = rCursor.Col();
135
0
            SCROW nOldRow = rCursor.Row();
136
0
            SCCOL nNewCol = mpViewData->GetCurX();
137
0
            SCROW nNewRow = mpViewData->GetCurY();
138
0
            mpDocShell->GetUndoManager()->AddUndoAction( std::make_unique<ScUndoConversion>(
139
0
                *mpDocShell, mpViewData->GetMarkData(),
140
0
                nOldCol, nOldRow, nTab, std::move(mxUndoDoc),
141
0
                nNewCol, nNewRow, nTab, std::move(mxRedoDoc),
142
0
                ScConversionParam( SC_CONVERSION_SPELLCHECK ) ) );
143
144
0
            sc::SetFormulaDirtyContext aCxt;
145
0
            mpDoc->SetAllFormulasDirty(aCxt);
146
147
0
            mpDocShell->SetDocumentModified();
148
0
        }
149
150
0
        mpViewData->SetSpellingView( nullptr );
151
0
        mpViewShell->KillEditView( true );
152
0
        mpDocShell->PostPaintGridAll();
153
0
        mpViewShell->UpdateInputHandler();
154
0
        mpDoc->EnableIdle(mbOldIdleEnabled);
155
0
    }
156
0
    mxEngine.reset();
157
0
    mxUndoDoc.reset();
158
0
    mxRedoDoc.reset();
159
0
    mxOldSel.reset();
160
0
    mxOldRangeList.clear();
161
0
    mpViewShell = nullptr;
162
0
    mpViewData = nullptr;
163
0
    mpDocShell = nullptr;
164
0
    mpDoc = nullptr;
165
0
    mbNeedNextObj = false;
166
0
    mbOldIdleEnabled = true;
167
0
}
168
169
void ScSpellDialogChildWindow::Init()
170
0
{
171
0
    if( mpViewShell )
172
0
        return;
173
0
    if( (mpViewShell = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() )) == nullptr  )
174
0
        return;
175
176
0
    mpViewData = &mpViewShell->GetViewData();
177
178
    // exit edit mode - TODO support spelling in edit mode
179
0
    if( mpViewData->HasEditView( mpViewData->GetActivePart() ) )
180
0
        ScModule::get()->InputEnterHandler();
181
182
0
    mxOldSel.reset( new ScSelectionState( *mpViewData ) );
183
184
0
    mpDocShell = mpViewData->GetDocShell();
185
0
    mpDoc = &mpDocShell->GetDocument();
186
187
0
    const ScAddress& rCursor = mxOldSel->GetCellCursor();
188
0
    SCCOL nCol = rCursor.Col();
189
0
    SCROW nRow = rCursor.Row();
190
0
    SCTAB nTab = rCursor.Tab();
191
192
0
    ScMarkData& rMarkData = mpViewData->GetMarkData();
193
194
0
    mxOldRangeList = new ScRangeList;
195
0
    rMarkData.FillRangeListWithMarks(mxOldRangeList.get(), true);
196
197
0
    rMarkData.MarkToMulti();
198
199
0
    switch( mxOldSel->GetSelectionType() )
200
0
    {
201
0
        case SC_SELECTTYPE_NONE:
202
0
        case SC_SELECTTYPE_SHEET:
203
0
        {
204
            // test if there is something editable
205
0
            ScEditableTester aTester = ScEditableTester::CreateAndTestSelection(*mpDoc, rMarkData);
206
0
            if( !aTester.IsEditable() )
207
0
            {
208
                // #i85751# Don't show an ErrorMessage here, because the vcl
209
                // parent of the InfoBox is not fully initialized yet.
210
                // This leads to problems in the modality behaviour of the
211
                // ScSpellDialogChildWindow.
212
213
                //mpViewShell->ErrorMessage( aTester.GetMessageId() );
214
0
                return;
215
0
            }
216
0
        }
217
0
        break;
218
219
        // edit mode exited, see TODO above
220
//        case SC_SELECTTYPE_EDITCELL:
221
//        break;
222
223
0
        default:
224
0
            OSL_FAIL( "ScSpellDialogChildWindow::Init - unknown selection type" );
225
0
    }
226
227
0
    mbOldIdleEnabled = mpDoc->IsIdleEnabled();
228
0
    mpDoc->EnableIdle(false);   // stop online spelling
229
230
    // *** create Undo/Redo documents *** -------------------------------------
231
232
0
    mxUndoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
233
0
    mxUndoDoc->InitUndo( *mpDoc, nTab, nTab );
234
0
    mxRedoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
235
0
    mxRedoDoc->InitUndo( *mpDoc, nTab, nTab );
236
237
0
    if ( rMarkData.GetSelectCount() > 1 )
238
0
    {
239
0
        for (const auto& rTab : rMarkData)
240
0
        {
241
0
            if( rTab != nTab )
242
0
            {
243
0
                mxUndoDoc->AddUndoTab( rTab, rTab );
244
0
                mxRedoDoc->AddUndoTab( rTab, rTab );
245
0
            }
246
0
        }
247
0
    }
248
249
    // *** create and init the edit engine *** --------------------------------
250
251
0
    mxEngine.reset( new ScSpellingEngine(
252
0
        mpDoc->GetEditEnginePool(), *mpViewData, mxUndoDoc.get(), mxRedoDoc.get(), LinguMgr::GetSpellChecker() ) );
253
0
    mxEngine->SetRefDevice( mpViewData->GetActiveWin()->GetOutDev() );
254
255
0
    mpViewShell->MakeEditView(*mxEngine, nCol, nRow);
256
0
    EditView* pEditView = mpViewData->GetEditView( mpViewData->GetActivePart() );
257
0
    mpViewData->SetSpellingView( pEditView );
258
0
    tools::Rectangle aRect( Point( 0, 0 ), Point( 0, 0 ) );
259
0
    pEditView->SetOutputArea( aRect );
260
0
    mxEngine->SetControlWord( EEControlBits::USECHARATTRIBS );
261
0
    mxEngine->EnableUndo( false );
262
0
    mxEngine->SetPaperSize( aRect.GetSize() );
263
0
    mxEngine->SetTextCurrentDefaults( OUString() );
264
0
    mxEngine->ClearModifyFlag();
265
266
0
    mbNeedNextObj = true;
267
0
}
268
269
bool ScSpellDialogChildWindow::IsSelectionChanged()
270
0
{
271
0
    if (!mxOldRangeList || !mpViewShell
272
0
        || (mpViewShell != dynamic_cast<ScTabViewShell*>(SfxViewShell::Current())))
273
0
        return true;
274
275
0
    if( EditView* pEditView = mpViewData->GetSpellingView() )
276
0
        if (&pEditView->getEditEngine() != mxEngine.get())
277
0
            return true;
278
279
0
    ScRangeList aCurrentRangeList;
280
0
    mpViewData->GetMarkData().FillRangeListWithMarks(&aCurrentRangeList, true);
281
282
0
    return (*mxOldRangeList != aCurrentRangeList);
283
0
}
284
285
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */