1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
24 #include <com/sun/star/beans/XMultiPropertySet.hpp>
25 #include <com/sun/star/beans/XPropertiesChangeListener.hpp>
26 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
27 #include <officecfg/Office/Common.hxx>
28 #include <editeng/eeitem.hxx>
29 #include <editeng/colritem.hxx>
30 #include <editeng/fhgtitem.hxx>
31 #include <editeng/fontitem.hxx>
32 #include <editeng/wghtitem.hxx>
33 #include <sqledit.hxx>
34 #include <cppuhelper/implbase.hxx>
35 #include <i18nlangtag/languagetag.hxx>
36 #include <svl/itempool.hxx>
37 #include <svl/itemset.hxx>
38 #include <vcl/commandevent.hxx>
39 #include <vcl/event.hxx>
40 #include <vcl/settings.hxx>
41 #include <vcl/specialchars.hxx>
42 #include <vcl/svapp.hxx>
44 using namespace dbaui
;
46 class SQLEditView::ChangesListener
:
47 public cppu::WeakImplHelper
< css::beans::XPropertiesChangeListener
>
50 explicit ChangesListener(SQLEditView
& editor
): editor_(editor
) {}
53 virtual ~ChangesListener() override
{}
55 virtual void SAL_CALL
disposing(css::lang::EventObject
const &) override
57 std::unique_lock
g(editor_
.m_mutex
);
58 editor_
.m_notifier
.clear();
61 virtual void SAL_CALL
propertiesChange(
62 css::uno::Sequence
< css::beans::PropertyChangeEvent
> const &) override
65 editor_
.ImplSetFont();
71 SQLEditView::SQLEditView(std::unique_ptr
<weld::ScrolledWindow
> xScrolledWindow
)
72 : m_xScrolledWindow(std::move(xScrolledWindow
))
73 , m_aUpdateDataTimer("dbaccess SQLEditView m_aUpdateDataTimer")
74 , m_aHighlighter(HighlighterLanguage::SQL
)
76 , m_bDisableInternalUndo(false)
78 m_xScrolledWindow
->connect_vadjustment_changed(LINK(this, SQLEditView
, ScrollHdl
));
81 void SQLEditView::DisableInternalUndo()
83 GetEditEngine()->EnableUndo(false);
84 m_bDisableInternalUndo
= true;
87 void SQLEditView::SetItemPoolFont(SfxItemPool
* pItemPool
)
89 OUString
sFontName(officecfg::Office::Common::Font::SourceViewFont::FontName::get().value_or(OUString()));
90 if (sFontName
.isEmpty())
92 vcl::Font
aTmpFont(OutputDevice::GetDefaultFont(DefaultFontType::FIXED
, Application::GetSettings().GetUILanguageTag().getLanguageType(), GetDefaultFontFlags::OnlyOne
));
93 sFontName
= aTmpFont
.GetFamilyName();
96 Size
aFontSize(0, officecfg::Office::Common::Font::SourceViewFont::FontHeight::get());
97 vcl::Font
aAppFont(sFontName
, aFontSize
);
99 pItemPool
->SetPoolDefaultItem(SvxFontItem(aAppFont
.GetFamilyType(), aAppFont
.GetFamilyName(),
100 "", PITCH_DONTKNOW
, RTL_TEXTENCODING_DONTKNOW
,
102 pItemPool
->SetPoolDefaultItem(SvxFontItem(aAppFont
.GetFamilyType(), aAppFont
.GetFamilyName(),
103 "", PITCH_DONTKNOW
, RTL_TEXTENCODING_DONTKNOW
,
104 EE_CHAR_FONTINFO_CJK
));
105 pItemPool
->SetPoolDefaultItem(SvxFontItem(aAppFont
.GetFamilyType(), aAppFont
.GetFamilyName(),
106 "", PITCH_DONTKNOW
, RTL_TEXTENCODING_DONTKNOW
,
107 EE_CHAR_FONTINFO_CTL
));
109 pItemPool
->SetPoolDefaultItem(
110 SvxFontHeightItem(aAppFont
.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT
));
111 pItemPool
->SetPoolDefaultItem(
112 SvxFontHeightItem(aAppFont
.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT_CJK
));
113 pItemPool
->SetPoolDefaultItem(
114 SvxFontHeightItem(aAppFont
.GetFontHeight() * 20, 100, EE_CHAR_FONTHEIGHT_CTL
));
117 void SQLEditView::makeEditEngine()
119 assert(!m_pItemPool
);
120 m_pItemPool
= EditEngine::CreatePool();
121 SetItemPoolFont(m_pItemPool
.get());
122 m_xEditEngine
.reset(new EditEngine(m_pItemPool
.get()));
125 void SQLEditView::SetDrawingArea(weld::DrawingArea
* pDrawingArea
)
127 WeldEditView::SetDrawingArea(pDrawingArea
);
129 EditEngine
& rEditEngine
= *GetEditEngine();
131 rEditEngine
.SetDefaultHorizontalTextDirection(EEHorizontalTextDirection::L2R
);
132 rEditEngine
.SetModifyHdl(LINK(this, SQLEditView
, ModifyHdl
));
133 rEditEngine
.SetStatusEventHdl(LINK(this, SQLEditView
, EditStatusHdl
));
135 m_aUpdateDataTimer
.SetTimeout(150);
136 m_aUpdateDataTimer
.SetInvokeHandler(LINK(this, SQLEditView
, ImplUpdateDataHdl
));
140 // Listen for change of Font and Color Settings:
141 // Using "this" in ctor is a little fishy, but should work here at least as
142 // long as there are no derivations:
143 m_listener
= new ChangesListener(*this);
144 css::uno::Reference
< css::beans::XMultiPropertySet
> n(
145 officecfg::Office::Common::Font::SourceViewFont::get(),
146 css::uno::UNO_QUERY_THROW
);
148 std::unique_lock
g(m_mutex
);
151 css::uno::Sequence
< OUString
> s
{ "FontHeight", "FontName" };
152 n
->addPropertiesChangeListener(s
, m_listener
);
153 m_ColorConfig
.AddListener(this);
156 SQLEditView::~SQLEditView()
158 css::uno::Reference
< css::beans::XMultiPropertySet
> n
;
160 std::unique_lock
g(m_mutex
);
164 n
->removePropertiesChangeListener(m_listener
);
166 m_ColorConfig
.RemoveListener(this);
169 void SQLEditView::SetTextAndUpdate(const OUString
& rNewText
)
175 IMPL_LINK_NOARG(SQLEditView
, ModifyHdl
, LinkParamNone
*, void)
179 m_aUpdateDataTimer
.Start();
182 IMPL_LINK_NOARG(SQLEditView
, ImplUpdateDataHdl
, Timer
*, void)
187 Color
SQLEditView::GetColorValue(TokenType aToken
)
189 return GetSyntaxHighlightColor(m_aColorConfig
, m_aHighlighter
.GetLanguage(), aToken
);
192 void SQLEditView::UpdateData()
195 EditEngine
& rEditEngine
= *GetEditEngine();
197 bool bModified
= rEditEngine
.IsModified();
198 bool bUndoEnabled
= rEditEngine
.IsUndoEnabled();
199 rEditEngine
.EnableUndo(false);
201 // syntax highlighting
202 for (sal_Int32 nLine
=0; nLine
< rEditEngine
.GetParagraphCount(); ++nLine
)
204 OUString
aLine( rEditEngine
.GetText( nLine
) );
206 ESelection
aAllLine(nLine
, 0, nLine
, EE_TEXTPOS_ALL
);
207 rEditEngine
.RemoveAttribs(aAllLine
, false, EE_CHAR_COLOR
);
208 rEditEngine
.RemoveAttribs(aAllLine
, false, EE_CHAR_WEIGHT
);
209 rEditEngine
.RemoveAttribs(aAllLine
, false, EE_CHAR_WEIGHT_CJK
);
210 rEditEngine
.RemoveAttribs(aAllLine
, false, EE_CHAR_WEIGHT_CTL
);
212 std::vector
<HighlightPortion
> aPortions
;
213 m_aHighlighter
.getHighlightPortions( aLine
, aPortions
);
214 for (auto const& portion
: aPortions
)
216 SfxItemSet
aSet(rEditEngine
.GetEmptyItemSet());
217 aSet
.Put(SvxColorItem(GetColorValue(portion
.tokenType
), EE_CHAR_COLOR
));
218 rEditEngine
.QuickSetAttribs(aSet
, ESelection(nLine
, portion
.nBegin
, nLine
, portion
.nEnd
));
222 rEditEngine
.ClearModifyFlag();
226 rEditEngine
.EnableUndo(bUndoEnabled
);
229 m_aModifyLink
.Call(nullptr);
234 void SQLEditView::DoBracketHilight(sal_uInt16 nKey
)
236 ESelection aCurrentPos
= m_xEditView
->GetSelection();
237 sal_Int32 nStartPos
= aCurrentPos
.nStartPos
;
238 const sal_uInt32 nStartPara
= aCurrentPos
.nStartPara
;
239 sal_uInt16 nCount
= 0;
244 case '\'': // no break
270 bool bUndoEnabled
= m_xEditEngine
->IsUndoEnabled();
271 m_xEditEngine
->EnableUndo(false);
273 sal_uInt32 nPara
= nStartPara
;
276 if (nPara
== nStartPara
&& nStartPos
== 0)
279 OUString
aLine( m_xEditEngine
->GetText( nPara
) );
284 for (sal_Int32 i
= (nPara
==nStartPara
) ? nStartPos
-1 : aLine
.getLength()-1; i
>0; --i
)
286 if (aLine
[i
] == nChar
)
290 SfxItemSet
aSet(m_xEditEngine
->GetEmptyItemSet());
291 aSet
.Put(SvxColorItem(Color(0,0,0), EE_CHAR_COLOR
));
292 aSet
.Put(SvxWeightItem(WEIGHT_ULTRABOLD
, EE_CHAR_WEIGHT
));
293 aSet
.Put(SvxWeightItem(WEIGHT_ULTRABOLD
, EE_CHAR_WEIGHT_CJK
));
294 aSet
.Put(SvxWeightItem(WEIGHT_ULTRABOLD
, EE_CHAR_WEIGHT_CTL
));
296 m_xEditEngine
->QuickSetAttribs(aSet
, ESelection(nPara
, i
, nPara
, i
+ 1));
297 m_xEditEngine
->QuickSetAttribs(aSet
, ESelection(nStartPara
, nStartPos
, nStartPara
, nStartPos
));
303 if (aLine
[i
] == nKey
)
308 m_xEditEngine
->EnableUndo(bUndoEnabled
);
311 Color
SQLEditView::GetSyntaxHighlightColor(const svtools::ColorConfig
& rColorConfig
, HighlighterLanguage eLanguage
, TokenType aToken
)
316 case HighlighterLanguage::SQL
:
320 case TokenType::Identifier
: aColor
= rColorConfig
.GetColorValue(svtools::SQLIDENTIFIER
).nColor
; break;
321 case TokenType::Number
: aColor
= rColorConfig
.GetColorValue(svtools::SQLNUMBER
).nColor
; break;
322 case TokenType::String
: aColor
= rColorConfig
.GetColorValue(svtools::SQLSTRING
).nColor
; break;
323 case TokenType::Operator
: aColor
= rColorConfig
.GetColorValue(svtools::SQLOPERATOR
).nColor
; break;
324 case TokenType::Keywords
: aColor
= rColorConfig
.GetColorValue(svtools::SQLKEYWORD
).nColor
; break;
325 case TokenType::Parameter
: aColor
= rColorConfig
.GetColorValue(svtools::SQLPARAMETER
).nColor
; break;
326 case TokenType::Comment
: aColor
= rColorConfig
.GetColorValue(svtools::SQLCOMMENT
).nColor
; break;
327 default: aColor
= Color(0,0,0);
331 case HighlighterLanguage::Basic
:
335 case TokenType::Identifier
: aColor
= Color(255,0,0); break;
336 case TokenType::Comment
: aColor
= Color(0,0,45); break;
337 case TokenType::Number
: aColor
= Color(204,102,204); break;
338 case TokenType::String
: aColor
= Color(0,255,45); break;
339 case TokenType::Operator
: aColor
= Color(0,0,100); break;
340 case TokenType::Keywords
: aColor
= Color(0,0,255); break;
341 case TokenType::Error
: aColor
= Color(0,255,255); break;
342 default: aColor
= Color(0,0,0);
346 default: aColor
= Color(0,0,0);
352 bool SQLEditView::KeyInput(const KeyEvent
& rKEvt
)
354 DoBracketHilight(rKEvt
.GetCharCode());
356 if (m_bDisableInternalUndo
)
358 KeyFuncType eFunc
= rKEvt
.GetKeyCode().GetFunction();
359 if (eFunc
== KeyFuncType::UNDO
|| eFunc
== KeyFuncType::REDO
)
363 return WeldEditView::KeyInput(rKEvt
);
366 bool SQLEditView::Command(const CommandEvent
& rCEvt
)
368 if (rCEvt
.GetCommand() == CommandEventId::ContextMenu
)
370 ::tools::Rectangle
aRect(rCEvt
.GetMousePosPixel(), Size(1, 1));
371 weld::Widget
* pPopupParent
= GetDrawingArea();
372 std::unique_ptr
<weld::Builder
> xBuilder(Application::CreateBuilder(pPopupParent
, "vcl/ui/editmenu.ui"));
373 std::unique_ptr
<weld::Menu
> xContextMenu(xBuilder
->weld_menu("menu"));
375 bool bEnableCut
= true;
376 bool bEnableCopy
= true;
377 bool bEnableDelete
= true;
378 bool bEnablePaste
= true;
379 bool bEnableSpecialChar
= true;
381 EditView
* pEditView
= GetEditView();
383 if (!pEditView
->HasSelection())
387 bEnableDelete
= false;
390 if (pEditView
->IsReadOnly())
393 bEnablePaste
= false;
394 bEnableDelete
= false;
395 bEnableSpecialChar
= false;
398 xContextMenu
->set_sensitive("cut", bEnableCut
);
399 xContextMenu
->set_sensitive("copy", bEnableCopy
);
400 xContextMenu
->set_sensitive("delete", bEnableDelete
);
401 xContextMenu
->set_sensitive("paste", bEnablePaste
);
402 xContextMenu
->set_sensitive("specialchar", bEnableSpecialChar
);
403 xContextMenu
->set_visible("undo", false);
404 xContextMenu
->set_visible("specialchar", vcl::GetGetSpecialCharsFunction() != nullptr);
406 OUString sCommand
= xContextMenu
->popup_at_rect(pPopupParent
, aRect
);
408 if (sCommand
== "cut")
410 else if (sCommand
== "copy")
412 else if (sCommand
== "paste")
414 else if (sCommand
== "delete")
415 pEditView
->DeleteSelected();
416 else if (sCommand
== "selectall")
418 sal_Int32 nPar
= m_xEditEngine
->GetParagraphCount();
421 sal_Int32 nLen
= m_xEditEngine
->GetTextLen(nPar
- 1);
422 pEditView
->SetSelection(ESelection(0, 0, nPar
- 1, nLen
));
425 else if (sCommand
== "specialchar")
427 OUString aChars
= vcl::GetGetSpecialCharsFunction()(pPopupParent
, m_xEditEngine
->GetStandardFont(0));
428 if (!aChars
.isEmpty())
430 pEditView
->InsertText(aChars
);
436 return WeldEditView::Command(rCEvt
);
439 void SQLEditView::EditViewScrollStateChange()
441 // editengine height has changed or editview scroll pos has changed
445 void SQLEditView::SetScrollBarRange()
447 EditEngine
*pEditEngine
= GetEditEngine();
450 if (!m_xScrolledWindow
)
452 EditView
* pEditView
= GetEditView();
456 int nVUpper
= pEditEngine
->GetTextHeight();
457 int nVCurrentDocPos
= pEditView
->GetVisArea().Top();
458 const Size
aOut(pEditView
->GetOutputArea().GetSize());
459 int nVStepIncrement
= aOut
.Height() * 2 / 10;
460 int nVPageIncrement
= aOut
.Height() * 8 / 10;
461 int nVPageSize
= aOut
.Height();
463 /* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has
466 lower = gtk_adjustment_get_lower
467 upper = gtk_adjustment_get_upper - gtk_adjustment_get_page_size
469 and requires that upper > lower or the deceleration animation never ends
471 nVPageSize
= std::min(nVPageSize
, nVUpper
);
473 m_xScrolledWindow
->vadjustment_configure(nVCurrentDocPos
, 0, nVUpper
,
474 nVStepIncrement
, nVPageIncrement
, nVPageSize
);
477 IMPL_LINK_NOARG(SQLEditView
, ScrollHdl
, weld::ScrolledWindow
&, void)
482 IMPL_LINK_NOARG(SQLEditView
, EditStatusHdl
, EditStatus
&, void)
487 void SQLEditView::DoScroll()
491 auto currentDocPos
= m_xEditView
->GetVisArea().Top();
492 auto nDiff
= currentDocPos
- m_xScrolledWindow
->vadjustment_get_value();
493 // we expect SetScrollBarRange callback to be triggered by Scroll
494 // to set where we ended up
495 m_xEditView
->Scroll(0, nDiff
);
499 void SQLEditView::ConfigurationChanged(utl::ConfigurationBroadcaster
*, ConfigurationHints
)
504 void SQLEditView::ImplSetFont()
506 // see SmEditWindow::DataChanged for a similar case
507 SetItemPoolFont(m_pItemPool
.get()); // change default font
508 // re-create with the new font
509 EditEngine
& rEditEngine
= *GetEditEngine();
510 OUString
aTxt(rEditEngine
.GetText());
512 SetTextAndUpdate(aTxt
);
515 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */