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 <string_view>
23 
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/drawing/XDrawView.hpp>
26 #include <com/sun/star/frame/XController.hpp>
27 #include <com/sun/star/view/XSelectionSupplier.hpp>
28 #include <com/sun/star/style/XStyle.hpp>
29 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
30 
31 #include <comphelper/sequence.hxx>
32 #include <sfx2/viewfrm.hxx>
33 #include <vcl/image.hxx>
34 #include <vcl/settings.hxx>
35 #include <vcl/virdev.hxx>
36 
37 #include <tools/debug.hxx>
38 #include <tools/diagnose_ex.h>
39 #include <svl/style.hxx>
40 #include <svl/stritem.hxx>
41 #include <sfx2/bindings.hxx>
42 #include <sfx2/app.hxx>
43 #include <sfx2/request.hxx>
44 #include <sfx2/dispatch.hxx>
45 #include <svx/svxids.hrc>
46 #include <svx/svdetc.hxx>
47 #include <editeng/boxitem.hxx>
48 #include <editeng/borderline.hxx>
49 #include <editeng/colritem.hxx>
50 #include <editeng/eeitem.hxx>
51 #include <svx/sdr/table/tabledesign.hxx>
52 #include <o3tl/enumrange.hxx>
53 
54 #include <TableDesignPane.hxx>
55 
56 #include <ViewShell.hxx>
57 #include <ViewShellBase.hxx>
58 #include <EventMultiplexer.hxx>
59 
60 using namespace ::com::sun::star;
61 using namespace ::com::sun::star::uno;
62 using namespace ::com::sun::star::drawing;
63 using namespace ::com::sun::star::container;
64 using namespace ::com::sun::star::beans;
65 using namespace ::com::sun::star::view;
66 using namespace ::com::sun::star::style;
67 using namespace ::com::sun::star::frame;
68 using namespace ::com::sun::star::lang;
69 using namespace ::com::sun::star::ui;
70 
71 namespace sd {
72 
73 const sal_Int32 nPreviewColumns = 5;
74 const sal_Int32 nPreviewRows = 5;
75 const sal_Int32 nCellWidth = 12; // one pixel is shared with the next cell!
76 const sal_Int32 nCellHeight = 7; // one pixel is shared with the next cell!
77 const sal_Int32 nBitmapWidth = (nCellWidth * nPreviewColumns) - (nPreviewColumns - 1);
78 const sal_Int32 nBitmapHeight = (nCellHeight * nPreviewRows) - (nPreviewRows - 1);
79 
80 const std::string_view gPropNames[CB_COUNT] =
81 {
82     "UseFirstRowStyle",
83     "UseLastRowStyle",
84     "UseBandingRowStyle",
85     "UseFirstColumnStyle",
86     "UseLastColumnStyle",
87     "UseBandingColumnStyle"
88 };
89 
TableDesignWidget(weld::Builder & rBuilder,ViewShellBase & rBase)90 TableDesignWidget::TableDesignWidget(weld::Builder& rBuilder, ViewShellBase& rBase)
91     : mrBase(rBase)
92     , m_xValueSet(new TableValueSet(rBuilder.weld_scrolled_window("previewswin", true)))
93     , m_xValueSetWin(new weld::CustomWeld(rBuilder, "previews", *m_xValueSet))
94 {
95     m_xValueSet->SetStyle(m_xValueSet->GetStyle() | WB_NO_DIRECTSELECT | WB_FLATVALUESET | WB_ITEMBORDER);
96     m_xValueSet->SetExtraSpacing(8);
97     m_xValueSet->setModal(false);
98     m_xValueSet->SetColor();
99     m_xValueSet->SetSelectHdl(LINK(this, TableDesignWidget, implValueSetHdl));
100 
101     for (sal_uInt16 i = CB_HEADER_ROW; i <= CB_BANDED_COLUMNS; ++i)
102     {
103         m_aCheckBoxes[i] = rBuilder.weld_check_button(OString(gPropNames[i].data(), gPropNames[i].size()));
104         m_aCheckBoxes[i]->connect_toggled(LINK(this, TableDesignWidget, implCheckBoxHdl));
105     }
106 
107     // get current controller and initialize listeners
108     try
109     {
110         mxView.set(mrBase.GetController(), UNO_QUERY);
111         addListener();
112 
113         Reference< XController > xController( mrBase.GetController(), UNO_SET_THROW );
114         Reference< XStyleFamiliesSupplier > xFamiliesSupp( xController->getModel(), UNO_QUERY_THROW );
115         Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() );
116         mxTableFamily.set( xFamilies->getByName( "table" ), UNO_QUERY_THROW );
117     }
118     catch (const Exception&)
119     {
120         TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPane::CustomAnimationPane()" );
121     }
122 
123     onSelectionChanged();
124     updateControls();
125 }
126 
~TableDesignWidget()127 TableDesignWidget::~TableDesignWidget()
128 {
129     removeListener();
130 }
131 
getBindings(ViewShellBase const & rBase)132 static SfxBindings* getBindings( ViewShellBase const & rBase )
133 {
134     if( rBase.GetMainViewShell() && rBase.GetMainViewShell()->GetViewFrame() )
135         return &rBase.GetMainViewShell()->GetViewFrame()->GetBindings();
136     else
137         return nullptr;
138 }
139 
getDispatcher(ViewShellBase const & rBase)140 static SfxDispatcher* getDispatcher( ViewShellBase const & rBase )
141 {
142     if( rBase.GetMainViewShell() && rBase.GetMainViewShell()->GetViewFrame() )
143         return rBase.GetMainViewShell()->GetViewFrame()->GetDispatcher();
144     else
145         return nullptr;
146 }
147 
IMPL_LINK_NOARG(TableDesignWidget,implValueSetHdl,ValueSet *,void)148 IMPL_LINK_NOARG(TableDesignWidget, implValueSetHdl, ValueSet*, void)
149 {
150     ApplyStyle();
151 }
152 
ApplyStyle()153 void TableDesignWidget::ApplyStyle()
154 {
155     try
156     {
157         OUString sStyleName;
158         sal_Int32 nIndex = static_cast< sal_Int32 >( m_xValueSet->GetSelectedItemId() ) - 1;
159 
160         if( (nIndex >= 0) && (nIndex < mxTableFamily->getCount()) )
161         {
162             Reference< XNameAccess > xNames( mxTableFamily, UNO_QUERY_THROW );
163             sStyleName = xNames->getElementNames()[nIndex];
164         }
165 
166         if( sStyleName.isEmpty() )
167             return;
168 
169         SdrView* pView = mrBase.GetDrawView();
170         if( mxSelectedTable.is() )
171         {
172             if( pView )
173             {
174                 SfxRequest aReq( SID_TABLE_STYLE, SfxCallMode::SYNCHRON, SfxGetpApp()->GetPool() );
175                 aReq.AppendItem( SfxStringItem( SID_TABLE_STYLE, sStyleName ) );
176 
177                 const rtl::Reference< sdr::SelectionController >& xController( pView->getSelectionController() );
178                 if( xController.is() )
179                     xController->Execute( aReq );
180 
181                 SfxBindings* pBindings = getBindings( mrBase );
182                 if( pBindings )
183                 {
184                     pBindings->Invalidate( SID_UNDO );
185                     pBindings->Invalidate( SID_REDO );
186                 }
187             }
188         }
189         else
190         {
191             SfxDispatcher* pDispatcher = getDispatcher( mrBase );
192             SfxStringItem aArg( SID_TABLE_STYLE, sStyleName );
193             pDispatcher->ExecuteList(SID_INSERT_TABLE, SfxCallMode::ASYNCHRON,
194                     { &aArg });
195         }
196     }
197     catch( Exception& )
198     {
199         TOOLS_WARN_EXCEPTION( "sd", "TableDesignWidget::implValueSetHdl()");
200     }
201 }
202 
IMPL_LINK_NOARG(TableDesignWidget,implCheckBoxHdl,weld::Toggleable &,void)203 IMPL_LINK_NOARG(TableDesignWidget, implCheckBoxHdl, weld::Toggleable&, void)
204 {
205     ApplyOptions();
206     FillDesignPreviewControl();
207 }
208 
ApplyOptions()209 void TableDesignWidget::ApplyOptions()
210 {
211     static const sal_uInt16 gParamIds[CB_COUNT] =
212     {
213         ID_VAL_USEFIRSTROWSTYLE, ID_VAL_USELASTROWSTYLE, ID_VAL_USEBANDINGROWSTYLE,
214         ID_VAL_USEFIRSTCOLUMNSTYLE, ID_VAL_USELASTCOLUMNSTYLE, ID_VAL_USEBANDINGCOLUMNSTYLE
215     };
216 
217     if( !mxSelectedTable.is() )
218         return;
219 
220     SfxRequest aReq( SID_TABLE_STYLE_SETTINGS, SfxCallMode::SYNCHRON, SfxGetpApp()->GetPool() );
221 
222     for( sal_uInt16 i = CB_HEADER_ROW; i <= CB_BANDED_COLUMNS; ++i )
223     {
224         aReq.AppendItem( SfxBoolItem( gParamIds[i], m_aCheckBoxes[i]->get_active() ) );
225     }
226 
227     SdrView* pView = mrBase.GetDrawView();
228     if( !pView )
229         return;
230 
231     const rtl::Reference< sdr::SelectionController >& xController( pView->getSelectionController() );
232     if( xController.is() )
233     {
234         xController->Execute( aReq );
235 
236         SfxBindings* pBindings = getBindings( mrBase );
237         if( pBindings )
238         {
239             pBindings->Invalidate( SID_UNDO );
240             pBindings->Invalidate( SID_REDO );
241         }
242     }
243 }
244 
onSelectionChanged()245 void TableDesignWidget::onSelectionChanged()
246 {
247     Reference< XPropertySet > xNewSelection;
248 
249     if( mxView.is() ) try
250     {
251         Reference< XSelectionSupplier >  xSel( mxView, UNO_QUERY_THROW );
252         Any aSel( xSel->getSelection() );
253         Sequence< XShape > xShapeSeq;
254         if( aSel >>= xShapeSeq )
255         {
256             if( xShapeSeq.getLength() == 1 )
257                 aSel <<= xShapeSeq[0];
258         }
259         else
260         {
261             Reference< XShapes > xShapes( aSel, UNO_QUERY );
262             if( xShapes.is() && (xShapes->getCount() == 1) )
263                 aSel = xShapes->getByIndex(0);
264         }
265 
266         Reference< XShapeDescriptor > xDesc( aSel, UNO_QUERY );
267         if( xDesc.is() && ( xDesc->getShapeType() == "com.sun.star.drawing.TableShape" || xDesc->getShapeType() == "com.sun.star.presentation.TableShape" ) )
268         {
269             xNewSelection.set( xDesc, UNO_QUERY );
270         }
271     }
272     catch( Exception& )
273     {
274         TOOLS_WARN_EXCEPTION( "sd", "sd::TableDesignWidget::onSelectionChanged()" );
275     }
276 
277     if( mxSelectedTable != xNewSelection )
278     {
279         mxSelectedTable = xNewSelection;
280         updateControls();
281     }
282 }
283 
Resize()284 void TableValueSet::Resize()
285 {
286     ValueSet::Resize();
287     // Calculate the number of rows and columns.
288     if( GetItemCount() <= 0 )
289         return;
290 
291     Size aValueSetSize = GetOutputSizePixel();
292 
293     Image aImage = GetItemImage(GetItemId(0));
294     Size aItemSize = aImage.GetSizePixel();
295 
296     aItemSize.AdjustHeight(10 );
297     int nColumnCount = (aValueSetSize.Width() - GetScrollWidth()) / aItemSize.Width();
298     if (nColumnCount < 1)
299         nColumnCount = 1;
300 
301     int nRowCount = (GetItemCount() + nColumnCount - 1) / nColumnCount;
302     if (nRowCount < 1)
303         nRowCount = 1;
304 
305     int nVisibleRowCount = (aValueSetSize.Height()+2) / aItemSize.Height();
306 
307     SetColCount (static_cast<sal_uInt16>(nColumnCount));
308     SetLineCount (static_cast<sal_uInt16>(nRowCount));
309 
310     if( !m_bModal )
311     {
312         WinBits nStyle = GetStyle() & ~WB_VSCROLL;
313         if( nRowCount > nVisibleRowCount )
314         {
315             nStyle |= WB_VSCROLL;
316         }
317         SetStyle( nStyle );
318     }
319 }
320 
TableValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)321 TableValueSet::TableValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)
322     : ValueSet(std::move(pScrolledWindow))
323     , m_bModal(false)
324 {
325 }
326 
StyleUpdated()327 void TableValueSet::StyleUpdated()
328 {
329     updateSettings();
330 }
331 
updateSettings()332 void TableValueSet::updateSettings()
333 {
334     if( !m_bModal )
335     {
336         Color aColor = Application::GetSettings().GetStyleSettings().GetWindowColor();
337         SetColor(aColor);
338         SetExtraSpacing(8);
339     }
340 }
341 
updateControls()342 void TableDesignWidget::updateControls()
343 {
344     static const bool gDefaults[CB_COUNT] = { true, false, true, false, false, false };
345 
346     const bool bHasTable = mxSelectedTable.is();
347 
348     for (sal_uInt16 i = CB_HEADER_ROW; i <= CB_BANDED_COLUMNS; ++i)
349     {
350         bool bUse = gDefaults[i];
351         if( bHasTable ) try
352         {
353             mxSelectedTable->getPropertyValue( OUString::createFromAscii(gPropNames[i]) ) >>= bUse;
354         }
355         catch( Exception& )
356         {
357             TOOLS_WARN_EXCEPTION( "sd", "sd::TableDesignWidget::updateControls()");
358         }
359         m_aCheckBoxes[i]->set_active(bUse);
360         m_aCheckBoxes[i]->set_sensitive(bHasTable);
361     }
362 
363     FillDesignPreviewControl();
364     m_xValueSet->updateSettings();
365     m_xValueSet->Resize();
366 
367     sal_uInt16 nSelection = 0;
368     if( mxSelectedTable.is() )
369     {
370         Reference< XNamed > xNamed( mxSelectedTable->getPropertyValue( "TableTemplate" ), UNO_QUERY );
371         if( xNamed.is() )
372         {
373             const OUString sStyleName( xNamed->getName() );
374 
375             Reference< XNameAccess > xNames( mxTableFamily, UNO_QUERY );
376             if( xNames.is() )
377             {
378                 Sequence< OUString > aNames( xNames->getElementNames() );
379                 sal_Int32 nIndex = comphelper::findValue(aNames, sStyleName);
380                 if (nIndex != -1)
381                     nSelection = static_cast<sal_uInt16>(nIndex) + 1;
382             }
383         }
384     }
385     m_xValueSet->SelectItem( nSelection );
386 }
387 
addListener()388 void TableDesignWidget::addListener()
389 {
390     Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,TableDesignWidget,EventMultiplexerListener) );
391     mrBase.GetEventMultiplexer()->AddEventListener( aLink );
392 }
393 
removeListener()394 void TableDesignWidget::removeListener()
395 {
396     Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,TableDesignWidget,EventMultiplexerListener) );
397     mrBase.GetEventMultiplexer()->RemoveEventListener( aLink );
398 }
399 
IMPL_LINK(TableDesignWidget,EventMultiplexerListener,tools::EventMultiplexerEvent &,rEvent,void)400 IMPL_LINK(TableDesignWidget,EventMultiplexerListener,
401     tools::EventMultiplexerEvent&, rEvent, void)
402 {
403     switch (rEvent.meEventId)
404     {
405         case EventMultiplexerEventId::CurrentPageChanged:
406         case EventMultiplexerEventId::EditViewSelection:
407             onSelectionChanged();
408             break;
409 
410         case EventMultiplexerEventId::MainViewRemoved:
411             mxView.clear();
412             onSelectionChanged();
413             break;
414 
415         case EventMultiplexerEventId::MainViewAdded:
416             mxView.set( mrBase.GetController(), UNO_QUERY );
417             onSelectionChanged();
418             break;
419 
420         default: break;
421     }
422 }
423 
424 namespace {
425 
426 struct CellInfo
427 {
428     Color maCellColor;
429     Color maTextColor;
430     std::shared_ptr<SvxBoxItem> maBorder;
431 
432     explicit CellInfo( const Reference< XStyle >& xStyle );
433 };
434 
435 }
436 
CellInfo(const Reference<XStyle> & xStyle)437 CellInfo::CellInfo( const Reference< XStyle >& xStyle )
438 : maBorder(std::make_shared<SvxBoxItem>(SDRATTR_TABLE_BORDER))
439 {
440     SfxStyleSheet* pStyleSheet = SfxUnoStyleSheet::getUnoStyleSheet( xStyle );
441     if( !pStyleSheet )
442         return;
443 
444     SfxItemSet& rSet = pStyleSheet->GetItemSet();
445 
446     // get style fill color
447     if( !GetDraftFillColor(rSet, maCellColor) )
448         maCellColor = COL_TRANSPARENT;
449 
450     // get style text color
451     const SvxColorItem* pTextColor = rSet.GetItem(EE_CHAR_COLOR);
452     if( pTextColor )
453         maTextColor = pTextColor->GetValue();
454     else
455         maTextColor = COL_TRANSPARENT;
456 
457     // get border
458     const SvxBoxItem* pBoxItem = rSet.GetItem( SDRATTR_TABLE_BORDER );
459     if( pBoxItem )
460         maBorder.reset(pBoxItem->Clone());
461 }
462 
463 typedef std::vector< std::shared_ptr< CellInfo > > CellInfoVector;
464 typedef std::shared_ptr< CellInfo > CellInfoMatrix[nPreviewColumns * nPreviewRows];
465 
466 namespace {
467 
468 struct TableStyleSettings
469 {
470     bool mbUseFirstRow;
471     bool mbUseLastRow;
472     bool mbUseFirstColumn;
473     bool mbUseLastColumn;
474     bool mbUseRowBanding;
475     bool mbUseColumnBanding;
476 
TableStyleSettingssd::__anon9d4f505e0211::TableStyleSettings477     TableStyleSettings()
478         : mbUseFirstRow(true)
479         , mbUseLastRow(false)
480         , mbUseFirstColumn(false)
481         , mbUseLastColumn(false)
482         , mbUseRowBanding(true)
483         , mbUseColumnBanding(false) {}
484 };
485 
486 }
487 
FillCellInfoVector(const Reference<XIndexAccess> & xTableStyle,CellInfoVector & rVector)488 static void FillCellInfoVector( const Reference< XIndexAccess >& xTableStyle, CellInfoVector& rVector )
489 {
490     DBG_ASSERT( xTableStyle.is() && (xTableStyle->getCount() == sdr::table::style_count ), "sd::FillCellInfoVector(), invalid table style!" );
491     if( !xTableStyle.is() )
492         return;
493 
494     try
495     {
496         rVector.resize( sdr::table::style_count );
497 
498         for( sal_Int32 nStyle = 0; nStyle < sdr::table::style_count; ++nStyle )
499         {
500             Reference< XStyle > xStyle( xTableStyle->getByIndex( nStyle ), UNO_QUERY );
501             if( xStyle.is() )
502                 rVector[nStyle] = std::make_shared<CellInfo>( xStyle );
503         }
504     }
505     catch(Exception&)
506     {
507         TOOLS_WARN_EXCEPTION( "sd", "sd::FillCellInfoVector()");
508     }
509 }
510 
FillCellInfoMatrix(const CellInfoVector & rStyle,const TableStyleSettings & rSettings,CellInfoMatrix & rMatrix)511 static void FillCellInfoMatrix( const CellInfoVector& rStyle, const TableStyleSettings& rSettings, CellInfoMatrix& rMatrix )
512 {
513     for( sal_Int32 nRow = 0; nRow < nPreviewColumns; ++nRow )
514     {
515         const bool bFirstRow = rSettings.mbUseFirstRow && (nRow == 0);
516         const bool bLastRow = rSettings.mbUseLastRow && (nRow == nPreviewColumns - 1);
517 
518         for( sal_Int32 nCol = 0; nCol < nPreviewColumns; ++nCol )
519         {
520             std::shared_ptr< CellInfo > xCellInfo;
521 
522             // first and last row win first, if used and available
523             if( bFirstRow )
524             {
525                 xCellInfo = rStyle[sdr::table::first_row_style];
526             }
527             else if( bLastRow )
528             {
529                 xCellInfo = rStyle[sdr::table::last_row_style];
530             }
531 
532             if( !xCellInfo )
533             {
534                 // next come first and last column, if used and available
535                 if( rSettings.mbUseFirstColumn && (nCol == 0)  )
536                 {
537                     xCellInfo = rStyle[sdr::table::first_column_style];
538                 }
539                 else if( rSettings.mbUseLastColumn && (nCol == nPreviewColumns-1) )
540                 {
541                     xCellInfo = rStyle[sdr::table::last_column_style];
542                 }
543             }
544 
545             if( !xCellInfo )
546             {
547                 if( rSettings.mbUseRowBanding )
548                 {
549                     if( (nRow & 1) == 0 )
550                     {
551                         xCellInfo = rStyle[sdr::table::even_rows_style];
552                     }
553                     else
554                     {
555                         xCellInfo = rStyle[sdr::table::odd_rows_style];
556                     }
557                 }
558             }
559 
560             if( !xCellInfo )
561             {
562                 if( rSettings.mbUseColumnBanding )
563                 {
564                     if( (nCol & 1) == 0 )
565                     {
566                         xCellInfo = rStyle[sdr::table::even_columns_style];
567                     }
568                     else
569                     {
570                         xCellInfo = rStyle[sdr::table::odd_columns_style];
571                     }
572                 }
573             }
574 
575             if( !xCellInfo )
576             {
577                 // use default cell style if non found yet
578                 xCellInfo = rStyle[sdr::table::body_style];
579             }
580 
581             rMatrix[(nCol * nPreviewColumns) + nRow] = xCellInfo;
582         }
583     }
584 }
585 
CreateDesignPreview(const Reference<XIndexAccess> & xTableStyle,const TableStyleSettings & rSettings,bool bIsPageDark)586 static BitmapEx CreateDesignPreview( const Reference< XIndexAccess >& xTableStyle, const TableStyleSettings& rSettings, bool bIsPageDark )
587 {
588     CellInfoVector aCellInfoVector(sdr::table::style_count);
589     FillCellInfoVector( xTableStyle, aCellInfoVector );
590 
591     CellInfoMatrix aMatrix;
592     FillCellInfoMatrix( aCellInfoVector, rSettings, aMatrix );
593 
594     // bbbbbbbbbbbb w = 12 pixel
595     // bccccccccccb h = 7 pixel
596     // bccccccccccb b = border color
597     // bcttttttttcb c = cell color
598     // bccccccccccb t = text color
599     // bccccccccccb
600     // bbbbbbbbbbbb
601 
602     ScopedVclPtr<VirtualDevice> pVirDev(VclPtr<VirtualDevice>::Create());
603     Size aBmpSize(nBitmapWidth, nBitmapHeight);
604     pVirDev->SetOutputSizePixel(aBmpSize);
605 
606     pVirDev->SetBackground( bIsPageDark ? COL_BLACK : COL_WHITE );
607     pVirDev->Erase();
608 
609     // first draw cell background and text line previews
610     sal_Int32 nY = 0;
611     sal_Int32 nRow;
612     for( nRow = 0; nRow < nPreviewRows; ++nRow, nY += nCellHeight-1 )
613     {
614         sal_Int32 nX = 0;
615         for( sal_Int32 nCol = 0; nCol < nPreviewColumns; ++nCol, nX += nCellWidth-1 )
616         {
617             std::shared_ptr< CellInfo > xCellInfo(aMatrix[(nCol * nPreviewColumns) + nRow]);
618 
619             Color aTextColor( COL_AUTO );
620             if( xCellInfo )
621             {
622                 // fill cell background
623                 const ::tools::Rectangle aRect( nX, nY, nX + nCellWidth - 1, nY + nCellHeight - 1 );
624 
625                 if( xCellInfo->maCellColor != COL_TRANSPARENT )
626                 {
627                     pVirDev->SetFillColor( xCellInfo->maCellColor );
628                     pVirDev->DrawRect( aRect );
629                 }
630 
631                 aTextColor = xCellInfo->maTextColor;
632             }
633 
634             // draw text preview line
635             if( aTextColor == COL_AUTO )
636                 aTextColor = bIsPageDark ? COL_WHITE : COL_BLACK;
637             pVirDev->SetLineColor( aTextColor );
638             const Point aPnt1( nX + 2, nY + ((nCellHeight - 1 ) >> 1) );
639             const Point aPnt2( nX + nCellWidth - 3, aPnt1.Y() );
640             pVirDev->DrawLine( aPnt1, aPnt2 );
641         }
642     }
643 
644     // second draw border lines
645     nY = 0;
646     for( nRow = 0; nRow < nPreviewRows; ++nRow, nY += nCellHeight-1 )
647     {
648         sal_Int32 nX = 0;
649         for( sal_Int32 nCol = 0; nCol < nPreviewColumns; ++nCol, nX += nCellWidth-1 )
650         {
651             std::shared_ptr< CellInfo > xCellInfo(aMatrix[(nCol * nPreviewColumns) + nRow]);
652 
653             if( xCellInfo )
654             {
655                 const Point aPntTL( nX, nY );
656                 const Point aPntTR( nX + nCellWidth - 1, nY );
657                 const Point aPntBL( nX, nY + nCellHeight - 1 );
658                 const Point aPntBR( nX + nCellWidth - 1, nY + nCellHeight - 1 );
659 
660                 sal_Int32 border_diffs[8] = { 0,-1, 0,1, -1,0, 1,0 };
661                 sal_Int32* pDiff = &border_diffs[0];
662 
663                 // draw top border
664                 for( SvxBoxItemLine nLine : o3tl::enumrange<SvxBoxItemLine>() )
665                 {
666                     const ::editeng::SvxBorderLine* pBorderLine = xCellInfo->maBorder->GetLine(nLine);
667                     if( !pBorderLine || ((pBorderLine->GetOutWidth() == 0) && (pBorderLine->GetInWidth()==0)) )
668                         continue;
669 
670                     sal_Int32 nBorderCol = nCol + *pDiff++;
671                     sal_Int32 nBorderRow = nRow + *pDiff++;
672                     if( (nBorderCol >= 0) && (nBorderCol < nPreviewColumns) && (nBorderRow >= 0) && (nBorderRow < nPreviewRows) )
673                     {
674                         // check border
675                         std::shared_ptr< CellInfo > xBorderInfo(aMatrix[(nBorderCol * nPreviewColumns) + nBorderRow]);
676                         if( xBorderInfo )
677                         {
678                             const ::editeng::SvxBorderLine* pBorderLine2 = xBorderInfo->maBorder->GetLine(static_cast<SvxBoxItemLine>(static_cast<int>(nLine)^1));
679                             if( pBorderLine2 && pBorderLine2->HasPriority(*pBorderLine) )
680                                 continue; // other border line wins
681                         }
682                     }
683 
684                     pVirDev->SetLineColor( pBorderLine->GetColor() );
685                     switch( nLine )
686                     {
687                     case SvxBoxItemLine::TOP: pVirDev->DrawLine( aPntTL, aPntTR ); break;
688                     case SvxBoxItemLine::BOTTOM: pVirDev->DrawLine( aPntBL, aPntBR ); break;
689                     case SvxBoxItemLine::LEFT: pVirDev->DrawLine( aPntTL, aPntBL ); break;
690                     case SvxBoxItemLine::RIGHT: pVirDev->DrawLine( aPntTR, aPntBR ); break;
691                     }
692                 }
693             }
694         }
695     }
696 
697     return pVirDev->GetBitmapEx(Point(0,0), aBmpSize);
698 }
699 
FillDesignPreviewControl()700 void TableDesignWidget::FillDesignPreviewControl()
701 {
702     sal_uInt16 nSelectedItem = m_xValueSet->GetSelectedItemId();
703     m_xValueSet->Clear();
704     try
705     {
706         TableStyleSettings aSettings;
707         if( mxSelectedTable.is() )
708         {
709             aSettings.mbUseFirstRow = m_aCheckBoxes[CB_HEADER_ROW]->get_active();
710             aSettings.mbUseLastRow = m_aCheckBoxes[CB_TOTAL_ROW]->get_active();
711             aSettings.mbUseRowBanding = m_aCheckBoxes[CB_BANDED_ROWS]->get_active();
712             aSettings.mbUseFirstColumn = m_aCheckBoxes[CB_FIRST_COLUMN]->get_active();
713             aSettings.mbUseLastColumn = m_aCheckBoxes[CB_LAST_COLUMN]->get_active();
714             aSettings.mbUseColumnBanding = m_aCheckBoxes[CB_BANDED_COLUMNS]->get_active();
715         }
716 
717         bool bIsPageDark = false;
718         if( mxView.is() )
719         {
720             Reference< XPropertySet > xPageSet( mxView->getCurrentPage(), UNO_QUERY );
721             if( xPageSet.is() )
722             {
723                 xPageSet->getPropertyValue("IsBackgroundDark") >>= bIsPageDark;
724             }
725         }
726 
727         sal_Int32 nCount = mxTableFamily->getCount();
728         for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) try
729         {
730             Reference< XIndexAccess > xTableStyle( mxTableFamily->getByIndex( nIndex ), UNO_QUERY );
731             if( xTableStyle.is() )
732                 m_xValueSet->InsertItem( sal::static_int_cast<sal_uInt16>( nIndex + 1 ), Image( CreateDesignPreview( xTableStyle, aSettings, bIsPageDark ) ) );
733         }
734         catch( Exception& )
735         {
736             TOOLS_WARN_EXCEPTION( "sd", "sd::TableDesignWidget::FillDesignPreviewControl()");
737         }
738         sal_Int32 nCols = 3;
739         sal_Int32 nRows = (nCount+2)/3;
740         m_xValueSet->SetColCount(nCols);
741         m_xValueSet->SetLineCount(nRows);
742         WinBits nStyle = m_xValueSet->GetStyle() & ~WB_VSCROLL;
743         m_xValueSet->SetStyle(nStyle);
744 
745         m_xValueSet->SetOptimalSize();
746         weld::DrawingArea* pDrawingArea = m_xValueSet->GetDrawingArea();
747         Size aSize = pDrawingArea->get_preferred_size();
748         aSize.AdjustWidth(10 * nCols);
749         aSize.AdjustHeight(10 * nRows);
750         pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
751 
752         m_xValueSet->Resize();
753     }
754     catch( Exception& )
755     {
756         TOOLS_WARN_EXCEPTION( "sd", "sd::TableDesignWidget::FillDesignPreviewControl()");
757     }
758     m_xValueSet->SelectItem(nSelectedItem);
759 }
760 
761 }
762 
763 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
764