Kaydet (Commit) 73859a1c authored tarafından Justin Luth's avatar Justin Luth

tdf#117721 draw ui: add .uno::SetOptimalColumnWidth

Optimize column width: Adjusts the width of the
selected columns to fit the content,
without changing the width of the table.
Any leftover space is distributed proportionately,
with thin columns growing slightly,
and wide columns growing much wider.

The implementation and results are different from how Writer
does it, but tables themselves are also very different in Draw.
So I don't think it needs to be handled identically.

Writer's implementation is really "minimalColumnWidth" anyway.

Change-Id: Ia10cfa9822d7eef3c4909a82c21535aa6668b143
Reviewed-on: https://gerrit.libreoffice.org/60078
Tested-by: Jenkins
Reviewed-by: 's avatarJustin Luth <justin_luth@sil.org>
üst f74b8882
......@@ -75,7 +75,7 @@ public:
SVX_DLLPRIVATE void onFormatTable( SfxRequest const & rReq );
SVX_DLLPRIVATE void MergeMarkedCells();
SVX_DLLPRIVATE void SplitMarkedCells();
SVX_DLLPRIVATE void DistributeColumns();
SVX_DLLPRIVATE void DistributeColumns( const bool bOptimize );
SVX_DLLPRIVATE void DistributeRows();
SVX_DLLPRIVATE void SetVertical( sal_uInt16 nSId );
......
......@@ -113,7 +113,7 @@ public:
void CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd);
// Table stuff
void DistributeColumns( sal_Int32 nFirstColumn, sal_Int32 nLastColumn );
void DistributeColumns( sal_Int32 nFirstColumn, sal_Int32 nLastColumn, const bool bOptimize );
void DistributeRows( sal_Int32 nFirstRow, sal_Int32 nLastRow );
css::uno::Reference< css::table::XTable > getTable() const;
......
......@@ -469,6 +469,7 @@ class SfxStringItem;
#define SID_ATTR_3D_INTERN ( SID_SVX_START + 422 )
#define SID_PSZ_FUNCTION ( SID_SVX_START + 423 )
// CAUTION! <424 > used by sfxids (!)
#define SID_TABLE_INSERT_COL_DLG ( SID_SVX_START + 426 )
#define SID_TABLE_INSERT_ROW_DLG ( SID_SVX_START + 427 )
#define SID_TABLE_PARAM_INSERT_AFTER ( SID_SVX_START + 428 )
......@@ -970,8 +971,12 @@ class SfxStringItem;
#define SID_MEASURE_DLG ( SID_SVX_START + 1176 )
#define SID_TABLE_OPTIMAL_COLUMN_WIDTH ( SID_SVX_START + 1187 )
#define SID_TABLE_OPTIMAL_ROW_HEIGHT ( SID_SVX_START + 1188 )
// IMPORTANT NOTE: adjust SID_SVX_FIRSTFREE, when adding new slot id
#define SID_SVX_FIRSTFREE ( SID_MEASURE_DLG + 1 )
#define SID_SVX_FIRSTFREE ( SID_TABLE_OPTIMAL_ROW_HEIGHT + 1 )
// Overflow check for slot IDs
#if SID_SVX_FIRSTFREE > SID_SVX_END
......
......@@ -1849,6 +1849,14 @@
<value>1</value>
</prop>
</node>
<node oor:name=".uno:SetOptimalColumnWidth" oor:op="replace">
<prop oor:name="Label" oor:type="xs:string">
<value xml:lang="en-US">Optimal Column Width</value>
</prop>
<prop oor:name="Properties" oor:type="xs:int">
<value>1</value>
</prop>
</node>
<node oor:name=".uno:DistributeColumns" oor:op="replace">
<prop oor:name="Label" oor:type="xs:string">
<value xml:lang="en-US">Distribute Columns Evenly</value>
......
......@@ -4073,6 +4073,23 @@ SfxBoolItem DisplayMasterObjects SID_DISPLAY_MASTER_OBJECTS
GroupId = SfxGroupId::View;
]
SfxVoidItem SetOptimalColumnWidth SID_TABLE_OPTIMAL_COLUMN_WIDTH
()
[
AutoUpdate = FALSE,
FastCall = TRUE,
ReadOnlyDoc = FALSE,
Toggle = FALSE,
Container = FALSE,
RecordAbsolute = FALSE,
RecordPerSet;
AccelConfig = TRUE,
MenuConfig = TRUE,
ToolBoxConfig = TRUE,
GroupId = SfxGroupId::Table;
]
SfxVoidItem DistributeColumns SID_TABLE_DISTRIBUTE_COLUMNS
()
[
......
......@@ -144,6 +144,12 @@ shell TableObjectBar
StateMethod = GetState;
]
SID_TABLE_OPTIMAL_COLUMN_WIDTH
[
ExecMethod = Execute;
StateMethod = GetState;
]
SID_TABLE_DISTRIBUTE_COLUMNS
[
ExecMethod = Execute;
......
......@@ -42,6 +42,7 @@
</menu:menu>
<menu:menu menu:id=".uno:ColumnMenu">
<menu:menupopup>
<menu:menuitem menu:id=".uno:SetOptimalColumnWidth"/>
<menu:menuitem menu:id=".uno:DistributeColumns"/>
<menu:menuseparator/>
<menu:menuitem menu:id=".uno:EntireColumn"/>
......
......@@ -41,6 +41,7 @@
</menu:menu>
<menu:menu menu:id=".uno:ColumnMenu">
<menu:menupopup>
<menu:menuitem menu:id=".uno:SetOptimalColumnWidth"/>
<menu:menuitem menu:id=".uno:DistributeColumns"/>
<menu:menuseparator/>
<menu:menuitem menu:id=".uno:EntireColumn"/>
......
......@@ -20,4 +20,5 @@
<toolbar:toolbar xmlns:toolbar="http://openoffice.org/2001/toolbar" xmlns:xlink="http://www.w3.org/1999/xlink">
<toolbar:toolbaritem xlink:href=".uno:DistributeColumns"/>
<toolbar:toolbaritem xlink:href=".uno:DistributeRows"/>
</toolbar:toolbar>
\ No newline at end of file
<toolbar:toolbaritem xlink:href=".uno:SetOptimalColumnWidth"/>
</toolbar:toolbar>
......@@ -42,6 +42,7 @@
</menu:menu>
<menu:menu menu:id=".uno:ColumnMenu">
<menu:menupopup>
<menu:menuitem menu:id=".uno:SetOptimalColumnWidth"/>
<menu:menuitem menu:id=".uno:DistributeColumns"/>
<menu:menuseparator/>
<menu:menuitem menu:id=".uno:EntireColumn"/>
......
......@@ -41,6 +41,7 @@
</menu:menu>
<menu:menu menu:id=".uno:ColumnMenu">
<menu:menupopup>
<menu:menuitem menu:id=".uno:SetOptimalColumnWidth"/>
<menu:menuitem menu:id=".uno:DistributeColumns"/>
<menu:menuseparator/>
<menu:menuitem menu:id=".uno:EntireColumn"/>
......
......@@ -20,4 +20,5 @@
<toolbar:toolbar xmlns:toolbar="http://openoffice.org/2001/toolbar" xmlns:xlink="http://www.w3.org/1999/xlink">
<toolbar:toolbaritem xlink:href=".uno:DistributeColumns"/>
<toolbar:toolbaritem xlink:href=".uno:DistributeRows"/>
</toolbar:toolbar>
\ No newline at end of file
<toolbar:toolbaritem xlink:href=".uno:SetOptimalColumnWidth"/>
</toolbar:toolbar>
......@@ -80,6 +80,7 @@ public:
SVX_DLLPRIVATE void SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, bool bClearAllItems);
void SetMergedItem(const SfxPoolItem& rItem);
SVX_DLLPRIVATE sal_Int32 calcPreferredWidth( const Size aSize );
SVX_DLLPRIVATE sal_Int32 getMinimumWidth();
SVX_DLLPRIVATE sal_Int32 getMinimumHeight();
......
......@@ -704,6 +704,25 @@ void Cell::SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, bool bClearAllIt
}
sal_Int32 Cell::calcPreferredWidth( const Size aSize )
{
if ( !hasText() )
return getMinimumWidth();
Outliner& rOutliner=static_cast< SdrTableObj& >( GetObject() ).ImpGetDrawOutliner();
rOutliner.SetPaperSize(aSize);
rOutliner.SetUpdateMode(true);
ForceOutlinerParaObject( OutlinerMode::TextObject );
if( GetOutlinerParaObject() )
rOutliner.SetText(*GetOutlinerParaObject());
sal_Int32 nPreferredWidth = const_cast<EditEngine&>(rOutliner.GetEditEngine()).CalcTextWidth();
rOutliner.Clear();
return GetTextLeftDistance() + GetTextRightDistance() + nPreferredWidth;
}
sal_Int32 Cell::getMinimumWidth()
{
return GetTextLeftDistance() + GetTextRightDistance() + 100;
......
......@@ -2418,12 +2418,12 @@ void SdrTableObj::CropTableModelToSelection(const CellPos& rStart, const CellPos
mpImpl->CropTableModelToSelection(rStart, rEnd);
}
void SdrTableObj::DistributeColumns( sal_Int32 nFirstColumn, sal_Int32 nLastColumn )
void SdrTableObj::DistributeColumns( sal_Int32 nFirstColumn, sal_Int32 nLastColumn, const bool bOptimize )
{
if( mpImpl.is() && mpImpl->mpLayouter )
{
TableModelNotifyGuard aGuard( mpImpl->mxTable.get() );
mpImpl->mpLayouter->DistributeColumns( maRect, nFirstColumn, nLastColumn );
mpImpl->mpLayouter->DistributeColumns( maRect, nFirstColumn, nLastColumn, bOptimize );
}
}
......
......@@ -476,7 +476,6 @@ void SvxTableController::GetState( SfxItemSet& rSet )
rSet.DisableItem(SID_TABLE_SPLIT_CELLS);
break;
case SID_OPTIMIZE_TABLE:
case SID_TABLE_DISTRIBUTE_COLUMNS:
case SID_TABLE_DISTRIBUTE_ROWS:
{
......@@ -490,8 +489,6 @@ void SvxTableController::GetState( SfxItemSet& rSet )
bDistributeColumns = aStart.mnCol != aEnd.mnCol;
bDistributeRows = aStart.mnRow != aEnd.mnRow;
}
if( !bDistributeColumns && !bDistributeRows )
rSet.DisableItem(SID_OPTIMIZE_TABLE);
if( !bDistributeColumns )
rSet.DisableItem(SID_TABLE_DISTRIBUTE_COLUMNS);
if( !bDistributeRows )
......@@ -1002,8 +999,12 @@ void SvxTableController::Execute( SfxRequest& rReq )
SplitMarkedCells();
break;
case SID_TABLE_OPTIMAL_COLUMN_WIDTH:
DistributeColumns(/*bOptimize=*/true);
break;
case SID_TABLE_DISTRIBUTE_COLUMNS:
DistributeColumns();
DistributeColumns(/*bOptimize=*/false);
break;
case SID_TABLE_DISTRIBUTE_ROWS:
......@@ -1292,7 +1293,7 @@ void SvxTableController::SplitMarkedCells()
}
}
void SvxTableController::DistributeColumns()
void SvxTableController::DistributeColumns(const bool bOptimize)
{
if(!checkTableObject())
return;
......@@ -1309,7 +1310,7 @@ void SvxTableController::DistributeColumns()
CellPos aStart, aEnd;
getSelectedCells( aStart, aEnd );
rTableObj.DistributeColumns( aStart.mnCol, aEnd.mnCol );
rTableObj.DistributeColumns( aStart.mnCol, aEnd.mnCol, bOptimize );
if( bUndo )
rModel.EndUndo();
......
......@@ -171,6 +171,21 @@ sal_Int32 TableLayouter::getColumnWidth( sal_Int32 nColumn ) const
return 0;
}
sal_Int32 TableLayouter::calcPreferredColumnWidth( sal_Int32 nColumn, Size aSize ) const
{
sal_Int32 nRet = 0;
if ( isValidColumn(nColumn) )
{
for ( sal_uInt32 nRow = 0; nRow < static_cast<sal_uInt32>(maRows.size()); ++nRow )
{
CellRef xCell( getCell( CellPos( nColumn, nRow ) ) );
if ( xCell.is() && !xCell->isMerged() && xCell->getColumnSpan() == 1 )
nRet = std::max( nRet, xCell->calcPreferredWidth(aSize) );
}
}
return nRet;
}
bool TableLayouter::isEdgeVisible( sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal ) const
{
......@@ -575,10 +590,7 @@ void TableLayouter::LayoutTableWidth( tools::Rectangle& rArea, bool bFit )
xColSet->getPropertyValue( gsSize ) >>= nColWidth;
}
maColumns[nCol].mnSize = nColWidth;
if( maColumns[nCol].mnSize < nMinWidth )
maColumns[nCol].mnSize = nMinWidth;
maColumns[nCol].mnSize = std::max( nColWidth, nMinWidth);
nCurrentWidth = o3tl::saturating_add(nCurrentWidth, maColumns[nCol].mnSize);
}
......@@ -1047,27 +1059,83 @@ void TableLayouter::UpdateBorderLayout()
}
void TableLayouter::DistributeColumns( ::tools::Rectangle& rArea, sal_Int32 nFirstCol, sal_Int32 nLastCol )
void TableLayouter::DistributeColumns( ::tools::Rectangle& rArea,
sal_Int32 nFirstCol,
sal_Int32 nLastCol,
const bool bOptimize )
{
if( mxTable.is() ) try
{
const sal_Int32 nColCount = getColumnCount();
Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_QUERY_THROW );
const Size aSize(0xffffff, 0xffffff);
//special case - optimize a single column
if ( bOptimize && nFirstCol == nLastCol )
{
const sal_Int32 nWish = calcPreferredColumnWidth(nFirstCol, aSize);
if ( nWish < getColumnWidth(nFirstCol) )
{
Reference< XPropertySet > xColSet( xCols->getByIndex(nFirstCol), UNO_QUERY_THROW );
xColSet->setPropertyValue( gsSize, Any( nWish ) );
//FitWidth automatically distributes the new excess space
LayoutTable( rArea, /*bFitWidth=*/true, /*bFitHeight=*/false );
}
}
if( (nFirstCol < 0) || (nFirstCol>= nLastCol) || (nLastCol >= nColCount) )
return;
sal_Int32 nAllWidth = 0;
float fAllWish = 0;
sal_Int32 nUnused = 0;
std::vector<sal_Int32> aWish(nColCount);
for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol )
nAllWidth += getColumnWidth(nCol);
sal_Int32 nWidth = nAllWidth / (nLastCol-nFirstCol+1);
const sal_Int32 nEqualWidth = nAllWidth / (nLastCol-nFirstCol+1);
Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_QUERY_THROW );
//pass 1 - collect unneeded space (from an equal width perspective)
if ( bOptimize )
{
for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol )
{
const sal_Int32 nIndex = nCol - nFirstCol;
aWish[nIndex] = calcPreferredColumnWidth(nCol, aSize);
fAllWish += aWish[nIndex];
if ( aWish[nIndex] < nEqualWidth )
nUnused += nEqualWidth - aWish[nIndex];
}
}
const sal_Int32 nDistributeExcess = nAllWidth - fAllWish;
sal_Int32 nWidth = nEqualWidth;
for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol )
{
if( nCol == nLastCol )
nWidth = nAllWidth; // last column get round errors
nWidth = nAllWidth; // last column gets rounding/logic errors
else if ( bOptimize && fAllWish )
{
//pass 2 - first come, first served when requesting from the
// unneeded pool, or proportionally allocate excess.
const sal_Int32 nIndex = nCol - nFirstCol;
if ( aWish[nIndex] > nEqualWidth + nUnused )
{
nWidth = nEqualWidth + nUnused;
nUnused = 0;
}
else
{
nWidth = aWish[nIndex];
if ( aWish[nIndex] > nEqualWidth )
nUnused -= aWish[nIndex] - nEqualWidth;
if ( nDistributeExcess > 0 )
nWidth += nWidth / fAllWish * nDistributeExcess;
}
}
Reference< XPropertySet > xColSet( xCols->getByIndex( nCol ), UNO_QUERY_THROW );
xColSet->setPropertyValue( gsSize, Any( nWidth ) );
......
......@@ -78,6 +78,7 @@ public:
sal_Int32 getRowHeight( sal_Int32 nRow ) const;
sal_Int32 getColumnWidth( sal_Int32 nColumn ) const;
sal_Int32 calcPreferredColumnWidth( sal_Int32 nColumn, Size aSize ) const;
sal_Int32 getMinimumColumnWidth( sal_Int32 nColumn );
......@@ -94,7 +95,7 @@ public:
sal_Int32 getHorizontalEdge( int nEdgeY, sal_Int32* pnMin, sal_Int32* pnMax );
sal_Int32 getVerticalEdge( int nEdgeX , sal_Int32* pnMin, sal_Int32* pnMax);
void DistributeColumns( ::tools::Rectangle& rArea, sal_Int32 nFirstCol, sal_Int32 nLastCol );
void DistributeColumns( ::tools::Rectangle& rArea, sal_Int32 nFirstCol, sal_Int32 nLastCol, const bool bOptimize );
void DistributeRows( ::tools::Rectangle& rArea, sal_Int32 nFirstRow, sal_Int32 nLastRow );
void dumpAsXml(struct _xmlTextWriter* pWriter) const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment