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 <sal/config.h>
21 
22 #include <sot/exchange.hxx>
23 #include <svx/strings.hrc>
24 #include <svx/svxids.hrc>
25 
26 #include <sfx2/viewsh.hxx>
27 #include <sfx2/objsh.hxx>
28 #include <sfx2/dispatch.hxx>
29 #include <sfx2/viewfrm.hxx>
30 #include <vcl/image.hxx>
31 #include <vcl/transfer.hxx>
32 
33 #include <colrctrl.hxx>
34 
35 #include <svx/svdview.hxx>
36 #include <svx/drawitem.hxx>
37 #include <svx/xfillit0.hxx>
38 #include <svx/xflclit.hxx>
39 #include <editeng/colritem.hxx>
40 #include <svx/xlineit0.hxx>
41 #include <svx/xlnclit.hxx>
42 #include <svx/xtable.hxx>
43 #include <svx/dialmgr.hxx>
44 #include <helpids.h>
45 #include <vcl/virdev.hxx>
46 
47 #include <com/sun/star/beans/NamedValue.hpp>
48 
49 using namespace com::sun::star;
50 
51 class SvxColorValueSetData final : public TransferDataContainer
52 {
53 private:
54     uno::Sequence<beans::NamedValue> m_Data;
55 
56     virtual void AddSupportedFormats() override;
57     virtual bool GetData(const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc) override;
58 
59 public:
SvxColorValueSetData()60     SvxColorValueSetData()
61     {
62     }
63 
SetData(const uno::Sequence<beans::NamedValue> & rData)64     void SetData(const uno::Sequence<beans::NamedValue>& rData)
65     {
66         m_Data = rData;
67         ClearFormats(); // invalidate m_aAny so new data will take effect
68     }
69 };
70 
AddSupportedFormats()71 void SvxColorValueSetData::AddSupportedFormats()
72 {
73     AddFormat( SotClipboardFormatId::XFA );
74 }
75 
GetData(const css::datatransfer::DataFlavor & rFlavor,const OUString &)76 bool SvxColorValueSetData::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
77 {
78     bool bRet = false;
79 
80     if( SotExchange::GetFormat( rFlavor ) == SotClipboardFormatId::XFA )
81     {
82         SetAny(uno::makeAny(m_Data));
83         bRet = true;
84     }
85 
86     return bRet;
87 }
88 
SetDrawingArea(weld::DrawingArea * pDrawingArea)89 void SvxColorValueSet_docking::SetDrawingArea(weld::DrawingArea* pDrawingArea)
90 {
91     SvxColorValueSet::SetDrawingArea(pDrawingArea);
92     SetAccessibleName(SvxResId(STR_COLORTABLE));
93     SetStyle(GetStyle() | WB_ITEMBORDER);
94 
95     m_xHelper.set(new SvxColorValueSetData);
96     rtl::Reference<TransferDataContainer> xHelper(m_xHelper);
97     SetDragDataTransferrable(xHelper, DND_ACTION_COPY);
98 }
99 
SvxColorValueSet_docking(std::unique_ptr<weld::ScrolledWindow> xWindow)100 SvxColorValueSet_docking::SvxColorValueSet_docking(std::unique_ptr<weld::ScrolledWindow> xWindow)
101     : SvxColorValueSet(std::move(xWindow))
102     , mbLeftButton(true)
103 {
104 }
105 
MouseButtonDown(const MouseEvent & rMEvt)106 bool SvxColorValueSet_docking::MouseButtonDown( const MouseEvent& rMEvt )
107 {
108     bool bRet;
109 
110     // For Mac still handle differently!
111     if( rMEvt.IsLeft() )
112     {
113         mbLeftButton = true;
114         bRet = SvxColorValueSet::MouseButtonDown( rMEvt );
115     }
116     else
117     {
118         mbLeftButton = false;
119         MouseEvent aMEvt( rMEvt.GetPosPixel(),
120                           rMEvt.GetClicks(),
121                           rMEvt.GetMode(),
122                           MOUSE_LEFT,
123                           rMEvt.GetModifier() );
124         bRet = SvxColorValueSet::MouseButtonDown( aMEvt );
125     }
126 
127     return bRet;
128 }
129 
MouseButtonUp(const MouseEvent & rMEvt)130 bool SvxColorValueSet_docking::MouseButtonUp( const MouseEvent& rMEvt )
131 {
132     bool bRet;
133 
134     // For Mac still handle differently!
135     if( rMEvt.IsLeft() )
136     {
137         mbLeftButton = true;
138         bRet = SvxColorValueSet::MouseButtonUp( rMEvt );
139     }
140     else
141     {
142         mbLeftButton = false;
143         MouseEvent aMEvt( rMEvt.GetPosPixel(),
144                           rMEvt.GetClicks(),
145                           rMEvt.GetMode(),
146                           MOUSE_LEFT,
147                           rMEvt.GetModifier() );
148         bRet = SvxColorValueSet::MouseButtonUp( aMEvt );
149     }
150     SetNoSelection();
151 
152     return bRet;
153 }
154 
StartDrag()155 bool SvxColorValueSet_docking::StartDrag()
156 {
157     sal_uInt16 nPos = GetSelectedItemId();
158     Color aItemColor( GetItemColor( nPos ) );
159     OUString sItemText( GetItemText( nPos ) );
160 
161     drawing::FillStyle eStyle = ((1 == nPos)
162                             ? drawing::FillStyle_NONE
163                             : drawing::FillStyle_SOLID);
164 
165     uno::Sequence<beans::NamedValue> props(2);
166     XFillColorItem const color(sItemText, aItemColor);
167     props[0].Name = "FillColor";
168     color.QueryValue(props[0].Value, 0);
169     XFillStyleItem const style(eStyle);
170     props[1].Name = "FillStyle";
171     style.QueryValue(props[1].Value, 0);
172 
173     m_xHelper->SetData(props);
174 
175     return false;
176 }
177 
178 constexpr sal_uInt16 gnLeftSlot = SID_ATTR_FILL_COLOR;
179 constexpr sal_uInt16 gnRightSlot = SID_ATTR_LINE_COLOR;
180 
SvxColorDockingWindow(SfxBindings * _pBindings,SfxChildWindow * pCW,vcl::Window * _pParent)181 SvxColorDockingWindow::SvxColorDockingWindow(SfxBindings* _pBindings, SfxChildWindow* pCW, vcl::Window* _pParent)
182     : SfxDockingWindow(_pBindings, pCW, _pParent,
183         "DockingColorWindow", "svx/ui/dockingcolorwindow.ui")
184     , pColorList()
185     , xColorSet(new SvxColorValueSet_docking(m_xBuilder->weld_scrolled_window("valuesetwin", true)))
186     , xColorSetWin(new weld::CustomWeld(*m_xBuilder, "valueset", *xColorSet))
187 {
188     SetText(SvxResId(STR_COLORTABLE));
189     SetQuickHelpText(SvxResId(RID_SVXSTR_COLORBAR));
190     SetSizePixel(LogicToPixel(Size(150, 22), MapMode(MapUnit::MapAppFont)));
191     SetHelpId(HID_CTRL_COLOR);
192 
193     xColorSet->SetSelectHdl( LINK( this, SvxColorDockingWindow, SelectHdl ) );
194     xColorSet->SetHelpId(HID_COLOR_CTL_COLORS);
195 
196     // Get the model from the view shell.  Using SfxObjectShell::Current()
197     // is unreliable when called at the wrong times.
198     SfxObjectShell* pDocSh = nullptr;
199     if (_pBindings != nullptr)
200     {
201         SfxDispatcher* pDispatcher = _pBindings->GetDispatcher();
202         if (pDispatcher != nullptr)
203         {
204             SfxViewFrame* pFrame = pDispatcher->GetFrame();
205             if (pFrame != nullptr)
206             {
207                 SfxViewShell* pViewShell = pFrame->GetViewShell();
208                 if (pViewShell != nullptr)
209                     pDocSh = pViewShell->GetObjectShell();
210             }
211         }
212     }
213 
214     if ( pDocSh )
215     {
216         const SfxPoolItem*  pItem = pDocSh->GetItem( SID_COLOR_TABLE );
217         if( pItem )
218         {
219             pColorList = static_cast<const SvxColorListItem*>(pItem)->GetColorList();
220             FillValueSet();
221         }
222     }
223 
224     Size aItemSize = xColorSet->CalcItemSizePixel(Size(SvxColorValueSet::getEntryEdgeLength(), SvxColorValueSet::getEntryEdgeLength()));
225     aItemSize.setWidth( aItemSize.Width() + SvxColorValueSet::getEntryEdgeLength() );
226     aItemSize.setWidth( aItemSize.Width() / 2 );
227     aItemSize.setHeight( aItemSize.Height() + SvxColorValueSet::getEntryEdgeLength() );
228     aItemSize.setHeight( aItemSize.Height() / 2 );
229 
230     if (_pBindings != nullptr)
231         StartListening(*_pBindings, DuplicateHandling::Prevent);
232 }
233 
~SvxColorDockingWindow()234 SvxColorDockingWindow::~SvxColorDockingWindow()
235 {
236     disposeOnce();
237 }
238 
dispose()239 void SvxColorDockingWindow::dispose()
240 {
241     EndListening( GetBindings() );
242     xColorSetWin.reset();
243     xColorSet.reset();
244     SfxDockingWindow::dispose();
245 }
246 
Notify(SfxBroadcaster &,const SfxHint & rHint)247 void SvxColorDockingWindow::Notify( SfxBroadcaster& , const SfxHint& rHint )
248 {
249     const SfxPoolItemHint* pPoolItemHint = dynamic_cast<const SfxPoolItemHint*>(&rHint);
250     if ( pPoolItemHint )
251         if (auto pColorListItem = dynamic_cast<const SvxColorListItem*>(pPoolItemHint->GetObject()))
252         {
253             // The list of colors has changed
254             pColorList = pColorListItem->GetColorList();
255             FillValueSet();
256         }
257 }
258 
FillValueSet()259 void SvxColorDockingWindow::FillValueSet()
260 {
261     if( !pColorList.is() )
262         return;
263 
264     xColorSet->Clear();
265 
266     xColorSet->addEntriesForXColorList(*pColorList, 2);
267 
268     // create the last entry for 'invisible/none'
269     const Size aColorSize(SvxColorValueSet::getEntryEdgeLength(), SvxColorValueSet::getEntryEdgeLength());
270     tools::Long nPtX = aColorSize.Width() - 1;
271     tools::Long nPtY = aColorSize.Height() - 1;
272     ScopedVclPtrInstance< VirtualDevice > pVD;
273 
274     pVD->SetOutputSizePixel( aColorSize );
275     pVD->SetLineColor( COL_BLACK );
276     pVD->SetBackground( Wallpaper( COL_WHITE ) );
277     pVD->DrawLine( Point(), Point( nPtX, nPtY ) );
278     pVD->DrawLine( Point( 0, nPtY ), Point( nPtX, 0 ) );
279 
280     BitmapEx aBmp( pVD->GetBitmapEx( Point(), aColorSize ) );
281 
282     xColorSet->InsertItem( sal_uInt16(1), Image(aBmp), SvxResId( RID_SVXSTR_INVISIBLE ) );
283 }
284 
Close()285 bool SvxColorDockingWindow::Close()
286 {
287     SfxBoolItem aItem( SID_COLOR_CONTROL, false );
288     GetBindings().GetDispatcher()->ExecuteList(SID_COLOR_CONTROL,
289             SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
290     SfxDockingWindow::Close();
291     return true;
292 }
293 
IMPL_LINK_NOARG(SvxColorDockingWindow,SelectHdl,ValueSet *,void)294 IMPL_LINK_NOARG(SvxColorDockingWindow, SelectHdl, ValueSet*, void)
295 {
296     SfxDispatcher* pDispatcher = GetBindings().GetDispatcher();
297     sal_uInt16 nPos = xColorSet->GetSelectedItemId();
298     Color  aColor( xColorSet->GetItemColor( nPos ) );
299     OUString aStr( xColorSet->GetItemText( nPos ) );
300 
301     if (xColorSet->IsLeftButton())
302     {
303         if ( gnLeftSlot == SID_ATTR_FILL_COLOR )
304         {
305             if ( nPos == 1 )        // invisible
306             {
307                 XFillStyleItem aXFillStyleItem( drawing::FillStyle_NONE );
308                 pDispatcher->ExecuteList(gnLeftSlot, SfxCallMode::RECORD,
309                         { &aXFillStyleItem });
310             }
311             else
312             {
313                 bool bDone = false;
314 
315                 // If we have a DrawView and we are in TextEdit mode, then
316                 // not the area color but the text color is assigned
317                 SfxViewShell* pViewSh = SfxViewShell::Current();
318                 if ( pViewSh )
319                 {
320                     SdrView* pView = pViewSh->GetDrawView();
321                     if ( pView && pView->IsTextEdit() )
322                     {
323                         SvxColorItem aTextColorItem( aColor, SID_ATTR_CHAR_COLOR );
324                         pDispatcher->ExecuteList(SID_ATTR_CHAR_COLOR,
325                                 SfxCallMode::RECORD, { &aTextColorItem });
326                         bDone = true;
327                     }
328                 }
329                 if ( !bDone )
330                 {
331                     XFillStyleItem aXFillStyleItem( drawing::FillStyle_SOLID );
332                     XFillColorItem aXFillColorItem( aStr, aColor );
333                     pDispatcher->ExecuteList(gnLeftSlot, SfxCallMode::RECORD,
334                             { &aXFillColorItem, &aXFillStyleItem });
335                 }
336             }
337         }
338         else if ( nPos != 1 )       // invisible
339         {
340             SvxColorItem aLeftColorItem( aColor, gnLeftSlot );
341             pDispatcher->ExecuteList(gnLeftSlot, SfxCallMode::RECORD,
342                     { &aLeftColorItem });
343         }
344     }
345     else
346     {
347         if ( gnRightSlot == SID_ATTR_LINE_COLOR )
348         {
349             if( nPos == 1 )     // invisible
350             {
351                 XLineStyleItem aXLineStyleItem( drawing::LineStyle_NONE );
352                 pDispatcher->ExecuteList(gnRightSlot, SfxCallMode::RECORD,
353                         { &aXLineStyleItem });
354             }
355             else
356             {
357                 // If the LineStyle is invisible, it is set to SOLID
358                 SfxViewShell* pViewSh = SfxViewShell::Current();
359                 if ( pViewSh )
360                 {
361                     SdrView* pView = pViewSh->GetDrawView();
362                     if ( pView )
363                     {
364                         SfxItemSet aAttrSet( pView->GetModel()->GetItemPool() );
365                         pView->GetAttributes( aAttrSet );
366                         if ( aAttrSet.GetItemState( XATTR_LINESTYLE ) != SfxItemState::DONTCARE )
367                         {
368                             drawing::LineStyle eXLS =
369                                 aAttrSet.Get( XATTR_LINESTYLE ).GetValue();
370                             if ( eXLS == drawing::LineStyle_NONE )
371                             {
372                                 XLineStyleItem aXLineStyleItem( drawing::LineStyle_SOLID );
373                                 pDispatcher->ExecuteList(gnRightSlot,
374                                     SfxCallMode::RECORD, { &aXLineStyleItem });
375                             }
376                         }
377                     }
378                 }
379 
380                 XLineColorItem aXLineColorItem( aStr, aColor );
381                 pDispatcher->ExecuteList(gnRightSlot, SfxCallMode::RECORD,
382                         { &aXLineColorItem });
383             }
384         }
385         else if ( nPos != 1 )       // invisible
386         {
387             SvxColorItem aRightColorItem( aColor, gnRightSlot );
388             pDispatcher->ExecuteList(gnRightSlot, SfxCallMode::RECORD,
389                     { &aRightColorItem });
390         }
391     }
392 }
393 
GetFocus()394 void SvxColorDockingWindow::GetFocus()
395 {
396     SfxDockingWindow::GetFocus();
397     if (xColorSet)
398     {
399         // Grab the focus to the color value set so that it can be controlled
400         // with the keyboard.
401         xColorSet->GrabFocus();
402     }
403 }
404 
EventNotify(NotifyEvent & rNEvt)405 bool SvxColorDockingWindow::EventNotify( NotifyEvent& rNEvt )
406 {
407     bool bRet = false;
408     if( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
409     {
410         KeyEvent aKeyEvt = *rNEvt.GetKeyEvent();
411         sal_uInt16   nKeyCode = aKeyEvt.GetKeyCode().GetCode();
412         switch( nKeyCode )
413         {
414             case KEY_ESCAPE:
415                 GrabFocusToDocument();
416                 bRet = true;
417                 break;
418         }
419     }
420 
421     return bRet || SfxDockingWindow::EventNotify(rNEvt);
422 }
423 
424 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
425