View | Details | Raw Unified | Return to issue 7500
Collapse All | Expand All

(-)sc/inc/attarray.hxx (-2 lines)
Lines 179-186 public: Link Here
179
							SCROW nStartRow, SCROW nEndRow ) const;
179
							SCROW nStartRow, SCROW nEndRow ) const;
180
	BOOL	IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const;
180
	BOOL	IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const;
181
181
182
	BOOL	TestInsertCol( SCROW nStartRow, SCROW nEndRow) const;
183
	BOOL	TestInsertRow( SCSIZE nSize ) const;
184
	void	InsertRow( SCROW nStartRow, SCSIZE nSize );
182
	void	InsertRow( SCROW nStartRow, SCSIZE nSize );
185
	void	DeleteRow( SCROW nStartRow, SCSIZE nSize );
183
	void	DeleteRow( SCROW nStartRow, SCSIZE nSize );
186
	void	DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex );
184
	void	DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex );
(-)sc/inc/column.hxx (-2 lines)
Lines 193-200 public: Link Here
193
									SCROW nEndRow = MAXROW ) const;
193
									SCROW nEndRow = MAXROW ) const;
194
	BOOL		IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const;
194
	BOOL		IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const;
195
195
196
	BOOL		TestInsertCol( SCROW nStartRow, SCROW nEndRow) const;
197
	BOOL		TestInsertRow( SCSIZE nSize ) const;
198
	void		InsertRow( SCROW nStartRow, SCSIZE nSize );
196
	void		InsertRow( SCROW nStartRow, SCSIZE nSize );
199
	void		DeleteRow( SCROW nStartRow, SCSIZE nSize );
197
	void		DeleteRow( SCROW nStartRow, SCSIZE nSize );
200
	void		DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex, USHORT nDelFlag );
198
	void		DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex, USHORT nDelFlag );
(-)sc/source/core/data/attarray.cxx (-51 lines)
Lines 2037-2093 BOOL ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW Link Here
2037
	return bEqual;
2037
	return bEqual;
2038
}
2038
}
2039
2039
2040
2041
BOOL ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
2042
{
2043
	//	horizontal zusammengefasste duerfen nicht herausgeschoben werden
2044
	//	(ob die ganze Zusammenfassung betroffen ist, ist hier nicht zu erkennen)
2045
2046
	BOOL bTest = TRUE;
2047
	if (!IsEmpty())
2048
	{
2049
		SCSIZE nIndex = 0;
2050
		if ( nStartRow > 0 )
2051
			Search( nStartRow, nIndex );
2052
2053
		for ( ; nIndex < nCount; nIndex++ )
2054
		{
2055
			if ( ((const ScMergeFlagAttr&)pData[nIndex].pPattern->
2056
						GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped() )
2057
			{
2058
				bTest = FALSE;						// darf nicht herausgeschoben werden
2059
				break;
2060
			}
2061
			if ( pData[nIndex].nRow >= nEndRow )	// Ende des Bereichs
2062
				break;
2063
		}
2064
	}
2065
	return bTest;
2066
}
2067
2068
2069
BOOL ScAttrArray::TestInsertRow( SCSIZE nSize ) const
2070
{
2071
	//	wenn die erste herausgeschobene Zeile vertikal ueberlappt ist,
2072
	//	wuerde eine kaputte Zusammenfassung uebrigbleiben
2073
2074
	if (pData)
2075
	{
2076
		//	MAXROW + 1 - nSize	= erste herausgeschobene Zeile
2077
2078
		SCSIZE nFirstLost = nCount-1;
2079
        while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) )
2080
			--nFirstLost;
2081
2082
		if ( ((const ScMergeFlagAttr&)pData[nFirstLost].pPattern->
2083
							GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() )
2084
			return FALSE;
2085
	}
2086
2087
	return TRUE;
2088
}
2089
2090
2091
void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
2040
void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
2092
{
2041
{
2093
	if (!pData)
2042
	if (!pData)
(-)sc/source/core/data/column.cxx (-105 lines)
Lines 1256-1366 void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol) Link Here
1256
}
1256
}
1257
1257
1258
1258
1259
BOOL ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
1260
{
1261
	if (!IsEmpty())
1262
	{
1263
		BOOL bTest = TRUE;
1264
		if (pItems)
1265
			for (SCSIZE i=0; (i<nCount) && bTest; i++)
1266
				bTest = (pItems[i].nRow < nStartRow) || (pItems[i].nRow > nEndRow)
1267
						|| !CellVisible(pItems[i].pCell);
1268
1269
		//	AttrArray testet nur zusammengefasste
1270
1271
		if ((bTest) && (pAttrArray))
1272
			bTest = pAttrArray->TestInsertCol(nStartRow, nEndRow);
1273
1274
		//!		rausgeschobene Attribute bei Undo beruecksichtigen
1275
1276
		return bTest;
1277
	}
1278
	else
1279
		return TRUE;
1280
}
1281
1282
1283
BOOL ScColumn::TestInsertRow( SCSIZE nSize ) const
1284
{
1285
    //  AttrArray only looks for merged cells
1286
1287
	if ( pItems && nCount )
1288
        return ( nSize <= sal::static_int_cast<SCSIZE>(MAXROW) &&
1289
                 pItems[nCount-1].nRow <= MAXROW-(SCROW)nSize && pAttrArray->TestInsertRow( nSize ) );
1290
	else
1291
		return pAttrArray->TestInsertRow( nSize );
1292
1293
#if 0
1294
	//!		rausgeschobene Attribute bei Undo beruecksichtigen
1295
1296
	if ( nSize > static_cast<SCSIZE>(MAXROW) )
1297
		return FALSE;
1298
1299
	SCSIZE nVis = nCount;
1300
	while ( nVis && !CellVisible(pItems[nVis-1].pCell) )
1301
		--nVis;
1302
1303
	if ( nVis )
1304
		return ( pItems[nVis-1].nRow <= MAXROW-nSize );
1305
	else
1306
		return TRUE;
1307
#endif
1308
}
1309
1310
1311
1312
BOOL ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
1313
{
1314
	if (!IsEmpty())
1315
	{
1316
		BOOL bTest = TRUE;
1317
		if (pItems)
1318
			for (SCSIZE i=0; (i<nCount) && bTest; i++)
1319
				bTest = ((pItems[i].nRow < nStartRow) && (pItems[i].nRow > nEndRow))
1320
						|| !CellVisible(pItems[i].pCell);
1321
1322
		//	AttrArray testet nur zusammengefasste
1323
1324
		if ((bTest) && (pAttrArray))
1325
			bTest = pAttrArray->TestInsertCol(nStartRow, nEndRow);
1326
1327
		//!		rausgeschobene Attribute bei Undo beruecksichtigen
1328
1329
		return bTest;
1330
	}
1331
	else
1332
		return TRUE;
1333
}
1334
1335
1336
BOOL ScColumn::TestInsertRow( SCSIZE nSize ) const
1337
{
1338
    //  AttrArray only looks for merged cells
1339
1340
	if ( pItems && nCount )
1341
        return ( nSize <= sal::static_int_cast<SCSIZE>(MAXROW) &&
1342
                 pItems[nCount-1].nRow <= MAXROW-(SCROW)nSize && pAttrArray->TestInsertRow( nSize ) );
1343
	else
1344
		return pAttrArray->TestInsertRow( nSize );
1345
1346
#if 0
1347
	//!		rausgeschobene Attribute bei Undo beruecksichtigen
1348
1349
	if ( nSize > static_cast<SCSIZE>(MAXROW) )
1350
		return FALSE;
1351
1352
	SCSIZE nVis = nCount;
1353
	while ( nVis && !CellVisible(pItems[nVis-1].pCell) )
1354
		--nVis;
1355
1356
	if ( nVis )
1357
		return ( pItems[nVis-1].nRow <= MAXROW-nSize );
1358
	else
1359
		return TRUE;
1360
#endif
1361
}
1362
1363
1364
void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
1259
void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
1365
{
1260
{
1366
	pAttrArray->InsertRow( nStartRow, nSize );
1261
	pAttrArray->InsertRow( nStartRow, nSize );
(-)sc/source/core/data/table2.cxx (-6 lines)
Lines 109-117 BOOL ScTable::TestInsertRow( SCCOL nStartCol, SCCOL nEndCol, SCSIZE nSize ) Link Here
109
	if ( nStartCol==0 && nEndCol==MAXCOL && pOutlineTable )
109
	if ( nStartCol==0 && nEndCol==MAXCOL && pOutlineTable )
110
		bTest = pOutlineTable->TestInsertRow(nSize);
110
		bTest = pOutlineTable->TestInsertRow(nSize);
111
111
112
	for (SCCOL i=nStartCol; (i<=nEndCol) && bTest; i++)
113
		bTest = aCol[i].TestInsertRow( nSize );
114
115
	return bTest;
112
	return bTest;
116
}
113
}
117
114
Lines 178-186 BOOL ScTable::TestInsertCol( SCROW nStartRow, SCROW nEndRow, SCSIZE nSize ) Link Here
178
	if ( nSize > static_cast<SCSIZE>(MAXCOL) )
175
	if ( nSize > static_cast<SCSIZE>(MAXCOL) )
179
		bTest = FALSE;
176
		bTest = FALSE;
180
177
181
	for (SCCOL i=MAXCOL; (i+static_cast<SCCOL>(nSize)>MAXCOL) && bTest; i--)
182
		bTest = aCol[i].TestInsertCol(nStartRow, nEndRow);
183
184
	return bTest;
178
	return bTest;
185
}
179
}
186
180
(-)sc/source/ui/docshell/docfunc.cxx (-45 / +111 lines)
Lines 1-7 Link Here
1
/*************************************************************************
1
/*************************************************************************
2
 *
2
 *
3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
 * 
4
 *
5
 * Copyright 2008 by Sun Microsystems, Inc.
5
 * Copyright 2008 by Sun Microsystems, Inc.
6
 *
6
 *
7
 * OpenOffice.org - a multi-platform office productivity suite
7
 * OpenOffice.org - a multi-platform office productivity suite
Lines 52-57 Link Here
52
#include <svtools/PasswordHelper.hxx>
52
#include <svtools/PasswordHelper.hxx>
53
53
54
#include <list>
54
#include <list>
55
#include <queue>
55
56
56
#include "docfunc.hxx"
57
#include "docfunc.hxx"
57
58
Lines 64-69 Link Here
64
#include "detdata.hxx"
65
#include "detdata.hxx"
65
#include "detfunc.hxx"
66
#include "detfunc.hxx"
66
#include "docpool.hxx"
67
#include "docpool.hxx"
68
#include "dociter.hxx"
67
#include "docsh.hxx"
69
#include "docsh.hxx"
68
#include "drwlayer.hxx"
70
#include "drwlayer.hxx"
69
#include "editutil.hxx"
71
#include "editutil.hxx"
Lines 1269-1275 BOOL ScDocFunc::InsertCells( const ScRange& rRange, InsCellCmd eCmd, Link Here
1269
	if (eCmd==INS_CELLSRIGHT)
1271
	if (eCmd==INS_CELLSRIGHT)
1270
		nMergeTestEndX = MAXCOL;
1272
		nMergeTestEndX = MAXCOL;
1271
1273
1272
	BOOL bCanDo = TRUE;
1273
	BOOL bNeedRefresh = FALSE;
1274
	BOOL bNeedRefresh = FALSE;
1274
1275
1275
	SCCOL nEditTestEndX = (eCmd==INS_INSCOLS) ? MAXCOL : nMergeTestEndX;
1276
	SCCOL nEditTestEndX = (eCmd==INS_INSCOLS) ? MAXCOL : nMergeTestEndX;
Lines 1282-1325 BOOL ScDocFunc::InsertCells( const ScRange& rRange, InsCellCmd eCmd, Link Here
1282
		return FALSE;
1283
		return FALSE;
1283
	}
1284
	}
1284
1285
1285
	if (pDoc->HasAttrib( nMergeTestStartX,nMergeTestStartY,nTab,
1286
							nMergeTestEndX,nMergeTestEndY,nTab,
1287
							HASATTR_MERGED | HASATTR_OVERLAPPED ))
1288
	{
1289
		if (eCmd==INS_CELLSRIGHT)
1290
			bNeedRefresh = TRUE;
1291
1292
		SCCOL nMergeStartX = nMergeTestStartX;
1293
		SCROW nMergeStartY = nMergeTestStartY;
1294
		SCCOL nMergeEndX   = nMergeTestEndX;
1295
		SCROW nMergeEndY   = nMergeTestEndY;
1296
1297
		pDoc->ExtendMerge( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
1298
		pDoc->ExtendOverlapped( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
1299
		if ( nMergeStartX != nMergeTestStartX || nMergeStartY != nMergeTestStartY ||
1300
			 nMergeEndX   != nMergeTestEndX   || nMergeEndY   != nMergeTestEndY )
1301
			bCanDo = FALSE;
1302
1303
		//!		? nur Start testen ?
1304
1305
		if (!bCanDo)
1306
			if ( eCmd==INS_INSCOLS || eCmd==INS_INSROWS )
1307
				if ( nMergeStartX == nMergeTestStartX && nMergeStartY == nMergeTestStartY )
1308
				{
1309
					bCanDo = TRUE;
1310
//					bNeedRefresh = TRUE;
1311
				}
1312
	}
1313
1314
	if (!bCanDo)
1315
	{
1316
		//!			auf Verschieben (Drag&Drop) zurueckfuehren !!!
1317
		//	"Kann nicht in zusammengefasste Bereiche einfuegen"
1318
		if (!bApi)
1319
			rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0);
1320
		return FALSE;
1321
	}
1322
1323
	//
1286
	//
1324
	//		ausfuehren
1287
	//		ausfuehren
1325
	//
1288
	//
Lines 1340-1345 BOOL ScDocFunc::InsertCells( const ScRange& rRange, InsCellCmd eCmd, Link Here
1340
		pDoc->BeginDrawUndo();
1303
		pDoc->BeginDrawUndo();
1341
	}
1304
	}
1342
1305
1306
    // #i8302 : we unmerge overwhelming ranges, before insertion
1307
    // all the actions are put in the same ListAction
1308
    String aUndo = ScGlobal::GetRscString( STR_UNDO_RESIZEMATRIX );
1309
    if (bRecord)
1310
      rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo );
1311
1312
	// Separation overwhelming ranges into two categories,
1313
	// in order to obtain a human-compliant behaviour when remerging
1314
    std::queue<ScRange> qGrowingRange;
1315
    std::queue<ScRange> qMovingRange;
1316
	if ( pDoc->HasAttrib( rRange, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
1317
	{
1318
		SCCOL nCol = -1;
1319
		SCROW nRow1 = -1;
1320
		SCROW nRow2 = -1;
1321
		printf("Iterator from : %d, %d to %d, %d\n",
1322
			   nStartCol, nStartRow, nEndCol, nEndRow);
1323
1324
		ScDocAttrIterator aIter( pDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow );
1325
		const ScPatternAttr* pPattern;
1326
		const ScMergeAttr* pMergeFlag;
1327
		const ScMergeFlagAttr* pMergeFlagAttr;
1328
		while ( ( pPattern = aIter.GetNext( nCol, nRow1, nRow2 ) ) != NULL )
1329
		{
1330
			printf("running on this Cell : %d, %d, %d", nCol, nRow1, nRow2);
1331
1332
			pMergeFlag = (const ScMergeAttr*) &pPattern->GetItem(ATTR_MERGE);
1333
			pMergeFlagAttr = (const ScMergeFlagAttr*) &pPattern->GetItem(ATTR_MERGE_FLAG);
1334
			if ( (pMergeFlag && pMergeFlag->IsMerged()) ||
1335
				 (pMergeFlagAttr && pMergeFlagAttr->IsOverlapped()) )
1336
			{
1337
				ScRange rrRange (nCol, nRow1, nTab);
1338
				pDoc->ExtendOverlapped(rrRange);
1339
				pDoc->ExtendMerge(rrRange, TRUE, TRUE);
1340
				if (rrRange.aStart.Col() == nCol && rrRange.aStart.Row() == nRow1) {
1341
					printf(" => moving range");
1342
					qMovingRange.push(rrRange);
1343
				} else {
1344
					printf(" => growing range");
1345
					qGrowingRange.push(rrRange);
1346
				}
1347
				UnmergeCells( rrRange, TRUE, TRUE );
1348
				printf(" => unmerged : %d, %d -> %d, %d\n",
1349
					   rrRange.aStart.Col(), rrRange.aStart.Row(),
1350
					   rrRange.aEnd.Col(), rrRange.aEnd.Row());
1351
			}
1352
			else {
1353
				printf(" => No overlap on this one\n");
1354
			}
1355
		}
1356
	}
1357
1358
1343
	switch (eCmd)
1359
	switch (eCmd)
1344
	{
1360
	{
1345
		case INS_CELLSDOWN:
1361
		case INS_CELLSDOWN:
Lines 1368-1373 BOOL ScDocFunc::InsertCells( const ScRange& rRange, InsCellCmd eCmd, Link Here
1368
			nPaintEndX = MAXCOL;
1384
			nPaintEndX = MAXCOL;
1369
			nPaintFlags |= PAINT_TOP;
1385
			nPaintFlags |= PAINT_TOP;
1370
			break;
1386
			break;
1387
		case INS_NONE:
1371
		default:
1388
		default:
1372
			DBG_ERROR("Falscher Code beim Einfuegen");
1389
			DBG_ERROR("Falscher Code beim Einfuegen");
1373
			bSuccess = FALSE;
1390
			bSuccess = FALSE;
Lines 1376-1381 BOOL ScDocFunc::InsertCells( const ScRange& rRange, InsCellCmd eCmd, Link Here
1376
1393
1377
	if ( bSuccess )
1394
	if ( bSuccess )
1378
	{
1395
	{
1396
        // #i8302 : we remerge growing ranges, with the new part inserted
1397
        while( !qGrowingRange.empty() )
1398
        {
1399
            ScRange rrRange = qGrowingRange.front();
1400
            switch (eCmd)
1401
            {
1402
			case INS_CELLSDOWN:
1403
			case INS_INSROWS:
1404
				rrRange.aEnd.IncRow(static_cast<SCsCOL>(nEndRow-nStartRow+1));
1405
				break;
1406
			case INS_CELLSRIGHT:
1407
			case INS_INSCOLS:
1408
				rrRange.aEnd.IncCol(static_cast<SCsCOL>(nEndCol-nStartCol+1));
1409
				break;
1410
			case INS_NONE:
1411
			default:
1412
				break;
1413
            }
1414
			MergeCells(rrRange, FALSE, TRUE, TRUE, FALSE);
1415
			printf("I have merged a growing range : %d, %d -> %d, %d\n",
1416
				   rrRange.aStart.Col(), rrRange.aStart.Row(),
1417
				   rrRange.aEnd.Col(), rrRange.aEnd.Row());
1418
            qGrowingRange.pop();
1419
        }
1420
        // #i8302 : we remerge moving ranges
1421
		while( !qMovingRange.empty() )
1422
		{
1423
            ScRange rrRange = qMovingRange.front();
1424
            switch (eCmd)
1425
            {
1426
			case INS_CELLSDOWN:
1427
			case INS_INSROWS:
1428
				rrRange.aEnd.IncRow(static_cast<SCsCOL>(nEndRow-nStartRow+1));
1429
				rrRange.aStart.IncRow(static_cast<SCsCOL>(nEndRow-nStartRow+1));
1430
				break;
1431
			case INS_CELLSRIGHT:
1432
			case INS_INSCOLS:
1433
				rrRange.aEnd.IncCol(static_cast<SCsCOL>(nEndCol-nStartCol+1));
1434
				rrRange.aStart.IncCol(static_cast<SCsCOL>(nEndCol-nStartCol+1));
1435
				break;
1436
			case INS_NONE:
1437
			default:
1438
				break;
1439
            }
1440
			MergeCells(rrRange, FALSE, TRUE, TRUE, FALSE);
1441
			printf("I have merged a moving range : %d, %d -> %d, %d\n",
1442
				   rrRange.aStart.Col(), rrRange.aStart.Row(),
1443
				   rrRange.aEnd.Col(), rrRange.aEnd.Row());
1444
			qMovingRange.pop();
1445
		}
1446
1379
		if ( bRecord )
1447
		if ( bRecord )
1380
		{
1448
		{
1381
			rDocShell.GetUndoManager()->AddUndoAction(
1449
			rDocShell.GetUndoManager()->AddUndoAction(
Lines 1414-1419 BOOL ScDocFunc::InsertCells( const ScRange& rRange, InsCellCmd eCmd, Link Here
1414
								 nPaintEndX,   nPaintEndY,   nEndTab,
1482
								 nPaintEndX,   nPaintEndY,   nEndTab,
1415
								 nPaintFlags,  nExtFlags);
1483
								 nPaintFlags,  nExtFlags);
1416
		aModificator.SetDocumentModified();
1484
		aModificator.SetDocumentModified();
1485
        if (bRecord)
1486
            rDocShell.GetUndoManager()->LeaveListAction();
1417
1487
1418
//!		pDocSh->UpdateOle(GetViewData());	// muss an der View bleiben
1488
//!		pDocSh->UpdateOle(GetViewData());	// muss an der View bleiben
1419
//!		CellContentChanged();				// muss an der View bleiben
1489
//!		CellContentChanged();				// muss an der View bleiben
Lines 3494-3500 BOOL ScDocFunc::MergeCells( const ScRange& rRange, BOOL bContents, BOOL bRecord, Link Here
3494
	if (bNeedContents && bContents)
3564
	if (bNeedContents && bContents)
3495
		pDoc->DoMergeContents( nTab, nStartCol,nStartRow, nEndCol,nEndRow );
3565
		pDoc->DoMergeContents( nTab, nStartCol,nStartRow, nEndCol,nEndRow );
3496
	pDoc->DoMerge( nTab, nStartCol,nStartRow, nEndCol,nEndRow );
3566
	pDoc->DoMerge( nTab, nStartCol,nStartRow, nEndCol,nEndRow );
3497
	
3567
3498
	if (bCenter)
3568
	if (bCenter)
3499
	{
3569
	{
3500
		pDoc->ApplyAttr( nStartCol, nStartRow, nTab, SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER ) );
3570
		pDoc->ApplyAttr( nStartCol, nStartRow, nTab, SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER ) );
Lines 4037-4043 BOOL ScDocFunc::InsertAreaLink( const String& rFile, const String& rFilter, Link Here
4037
4107
4038
	return TRUE;
4108
	return TRUE;
4039
}
4109
}
4040
4041
4042
4043

Return to issue 7500