Alex Thurgood wrote:
Besser wäres natürlich, wenn ich die Dateien nicht vergessen hätte :-o
Alex
REM ***** BASIC *****
option explicit
sub SWsortUp()
thisComponent.lockcontrollers
SWSort true
thisComponent.unlockcontrollers
end sub
sub SWsortDown()
thisComponent.lockcontrollers
SWSort false
thisComponent.unlockcontrollers
end sub
sub SWsort(blnUpDown)
Dim oSheet ' The chosen
Calc Sheet
Dim oListe as Object ' The area to be sorted
Dim intListeStartSpalte '
Dim intListeEndSpalte '
Dim lngListeStartZeile '
Dim lngListeEndZeile '
Dim intListeAnzSpalten '
Dim lngListeAnzZeilen '
Dim intKritSpalte as Integer ' Number of Columns to be used for
sorting
Dim blnUeberschriften ' Does the list include column
headers?
Dim i as Integer ' Runtime integer
variable
Dim oRange as Object ' Helper variable for the
selected cell area
Dim aSortFields(1) as New com.sun.star.table.TableSortField
Dim aSortDesc(1) as New com.sun.star.beans.PropertyValue
'The chosen Calc sheet
oSheet = ThisComponent.CurrentController.ActiveSheet
' The area selected by the user
oListe = thisComponent.CurrentSelection
' Only one selected area is allowed, multiple zones won't work
if oListe.supportsService("com.sun.star.sheet.SheetCellRanges") then
msgbox "Multi-zone sorting non-functional!",,"© Ingenieurbüro
Weigel"
exit sub
end if
'Column determination for the active cell
oRange =
thisComponent.createInstance("com.sun.star.sheet.SheetCellRanges")
ThisComponent.CurrentController.Select(oRange)
intKritSpalte = ThisComponent.CurrentSelection.getCellAddress.Column
ThisComponent.CurrentController.Select(oListe)
'Selection of the list area, if exactly one cell has already been
selected
'(Tip: use Calc's own Sort recognition procedure)
SelectCurrentRange
'Lines and columns of the area to be sorted
intListeStartSpalte =
ThisComponent.CurrentSelection.getRangeAddress.StartColumn
intListeEndSpalte =
ThisComponent.CurrentSelection.getRangeAddress.EndColumn
intListeAnzSpalten = intListeEndSpalte - intListeStartSpalte
lngListeStartZeile =
ThisComponent.CurrentSelection.getRangeAddress.StartRow
lngListeEndZeile = ThisComponent.CurrentSelection.getRangeAddress.EndRow
lngListeAnzZeilen = lngListeEndZeile - lngListeStartZeile + 1
'Number of sort columns within the area to be sorted
intKritSpalte = intKritSpalte - intListeStartSpalte
if lngListeAnzZeilen = 1 then exit sub
'Column headers ?
blnUeberschriften = false
'The first line is interpreted as the column headers if the cells of
the first and second lines contain different data types
for i=intListeStartSpalte to intListeEndSpalte
if
oSheet.getCellByPosition(i,lngListeStartZeile).FormulaResultType <>
oSheet.getCellByPosition(i,lngListeStartZeile+1).FormulaResultType and _
oSheet.getCellByPosition(i,lngListeStartZeile).FormulaResultType <> 0 and _
oSheet.getCellByPosition(i,lngListeStartZeile+1).FormulaResultType <> 0 then
blnUeberschriften = true
exit for
end if
next i
if blnUeberschriften = false then
'The first line is also interpreted as the column headers,
'if the cells of the first and second lines contain the same data
types, but have different formatting styles
for i=intListeStartSpalte to intListeEndSpalte
if
oSheet.getCellByPosition(i,lngListeStartZeile).CellStyle <>
oSheet.getCellByPosition(i,lngListeStartZeile+1).CellStyle then
blnUeberschriften = true
exit for
end if
next i
end if
If blnUeberschriften and lngListeAnzZeilen > 1 then
lngListeStartZeile = lngListeStartZeile + 1
lngListeAnzZeilen = lngListeAnzZeilen -1
end if
if lngListeAnzZeilen = 1 then exit sub
'Insert a helper column
oSheet.Columns.insertByIndex(intListeEndSpalte+1,1)
'enumerate the existing order in the helper column
for i=lngListeStartZeile to lngListeEndZeile
oSheet.getCellByPosition(intListeEndSpalte+1,i).value=i
next i
oListe
=oSheet.getCellRangeByPosition(intListeStartSpalte,lngListeStartZeile,intListeEndSpalte+1,lngListeEndZeile)
'Sort properties
aSortFields(0).Field = intKritSpalte 'Columns in which the
user has set the active cell
aSortFields(0).IsAscending = blnUpDown
aSortFields(0).IsCaseSensitive = false
aSortFields(1).Field = intListeEndSpalte+1 'Helper column with existing
order
aSortFields(1).IsAscending = true
aSortFields(1).IsCaseSensitive = false
aSortDesc(0).Name = "SortFields"
aSortDesc(0).Value = aSortFields()
aSortDesc(1).Name = "ContainsHeader"
aSortDesc(1).Value = false
oListe.sort(aSortDesc())
'remove helper column
oSheet.Columns.removeByIndex(intListeEndSpalte+1,1)
oListe
=oSheet.getCellRangeByPosition(intListeStartSpalte,lngListeStartZeile,intListeEndSpalte,lngListeEndZeile)
ThisComponent.CurrentController.Select(oListe)
end sub
sub SelectCurrentRange
dim oDisp as object
dim oDoc as object
dim Array()
oDoc = ThisComponent.CurrentController.Frame
oDisp = createUnoService("com.sun.star.frame.DispatchHelper")
oDisp.executeDispatch(oDoc, ".uno:SortAscending", "", 0, Array())
oDisp.executeDispatch(ThisComponent.CurrentController.Frame,".uno:Undo", "",0,
Array())
End Sub
Whilst migrating from Microsoft Excel to OpenOffice.org, I discovered that Calc
can only sort Lists using at the most three simultaneous criteria.
The problem stems from the fact that Calc doesn't use any reliable sort
algorithm. Reliable sort algorithms take into account the relative order of
elements which, when compared to their position are equivalent, and do not
change, whereas unreliable sort procedures do not guarantee such a behaviour.
This means, and contrary to what is found in Excel, that with Calc you can not
build on a previously constructed sort order.
As an example to clarify the situation:
If you carry out several subsequent sorts in Excel, irrespective of whether
this is done via the menu Data|Sort or via the button in the toolbar, the
subsequent sorts all build on the order established by the previous sort. In
this way it is possible to organise any desired sort hierarchy according to
multiple sort criteria.
Exercise:
A business turnover list should be sorted according to 5 criteria,
... the first line should sort the Sales Rep
... within the Sales Rep list by Region
... within the Region by Article Group
... within the Article Group by Customer Group
... within the Customer Group by Date.
Solution A using the Sort Toolbar button:
Sort Liste
... first using the Date
... then using the Customer Group
... then using the Article Group
... then using the Region
... then the Sales Rep
Solution B using the Data|Sort menu:
Sort List
... first using 1. Article Group, 2. Customer Group, 3. Date
... then again with 1. Sales Rep, 2. Region
If you try to do this with Calc, Solution A fails because of Issue 7277 (sorts
are always carried out from the first column and not from the column in which
the active cell is to be found).
Solution B also fails because Calc throws away the pre-existing sort order at
every new sort command. This comes down to the fact that Calc uses an
unreliable sort method (Issue 20491).
A further disadvantage also rears its ugly head when using Calc:
Although Calc, like Excel, is capable of automatically recognising the area of
the worksheet in which the list is to be found, for this to work properly, the
user has to have previously selected a single cell within the list range (and
not a zone covering several cells). Once the cell has been selected, the sort
program attempts to determine the limits of the list to be sorted in all four
directions. In such a case, the program either meets the boundary of the sheet
(for example, upper left), or it finds a line or column that has no entries
whatsoever corresponding to the height or breadth of the list.
Calc can also detect whether the list contains a column header in the first
line, so that this line is not included in the sort procedure. To do this, it
compares the data types and the formats of the first and second lines. If the
two are not the same, Calc interprets the first as the column header.
The problem with Calc is that this recognition only works if the user goes
through the menu entry Data|Sort. In this case, the option "Zone includes
column headers" is automatically activated. If you use the toolbar button
however, Calc always sorts the first line as well as the rest. This odd
behaviour can only be avoided by pre-selecting the area to be sorted, and
voluntarily avoiding selection of the column headers. Not only is this way of
doing things time consuming, but also goes against the basic rules established
in Excel, whereby the user only has to explicitly select one cell within the
list. These basic rules are followed by Calc with the AutoFilter, Datapilot and
Sort using the menu entry Data|Sort, but not when attempting to the same thing
using the Sort toolbar button.
The macro presented here using OpenOffice.org Basic proposes an improved sort
mechanism that has the following improvements:
o reliable sorts
o the possibility of using multiple sort criteria by determining the
pre-existing sort order of previous sorts
o sorting using the column in which the active cell has been selected
o recognises column headers, if present
The macro works as follows:
Reliables sorts are not conditioned on the use of a preprogrammed sort
algorithm. The macro uses a feature that is already present in the unreliable
Calc sort algorithm in order to obtain reliable results. From the user's point
of view, the macro only ever sorts according to one criterium per sort
operation. In reality, the macro creates a temporary extra column, in which the
order obtained from the previous sort operation is enumerated. This column
serves as a second criterium for each sort operation. In this way, the
pre-existing sort order is maintained, so long as the sort order isn't modified
by the current sort criterium. This is known as reliable sorting.
Once reliable sorting has been established, it is possible to use as many sort
criteria as is wished. The only drawback is that you have to carry out more
sort operations, and use the criteria in reverse order hierarchy. (See Solution
A above)
The sort criteria to be used in the current sort operation is always defined as
the column in which the currently active cell is to be found. A sort operation
is therefore usually attainable using just two mouse clicks: (1) click on any
single cell within the list and in the column to be used as sort criterium. (2)
click in the toolbar, to get the macro sort in ascending or descending order.
It is only now necessary to (painstakingly) preselect the zone to be sorted in
exceptional circumstances, for example, when that zone is not to be found in a
list surrounded by empty cells.
The macro also recognises whether the first line contains headers. It does this
by comparing the data types of the cell content of every column in the first
and second lines. If these are not all identical, then they are considered to
be headers. In some rare cases, a list may contain identical data types in all
columns to those of your headers (e.g. all text content). The macro thus also
checks to see whether there is a difference in formatting styles between the
first and second lines, which corresponds to general use case scenario within
OpenOffice.org, whereby different structural elements of a document should have
different formatting styles attributed to them.
Unfortunately, execution of the macro can not be undone, unlike mouse click
functions. It is possible to find out more about this in the "Cancel"-History
of the individual steps that were carried out by the macro (see Issue 53097).
Future versions of Calc may bring improvements in this area.
Pimp my Calc : how do I integrate this macro into my OpenOffice.org
installation ?
(1) You'll find the source code for the macro here : PimpMyCalc.bas
(2) Within OpenOffice.org choose Tools | Macros | Manage Macros |
OpenOffice.org Basic...
(3) Click on Manage...
(4) Select "My Macros" and the click on New...
(5) Enter in any name that you wish for your new Module. Then click on "OK".
(6) Click on Edit... The new module is now open in the Basic IDE.
(7) Replace the existing text in this document with that copied from
PimpMyCalc.bas
(8) Close the Basic-IDE Editor.
(9) In the Tools | Adapt... | Toolbars menu entry choose a toolbar or create a
new one.
(10) Click on Add... and then choose on the left under "OpenOffice.org Macros"
the newly added module. Select the entry "SWsortUp" on the right hand side and
click on Add. This is the macro for ascending sorts. Add the corresponding
"SWsortDown" routine for descending sorts.
(11) Using the Change button and the command Swap Icon... , you can choose
which icon is to be displayed in the toolbar for each of these macros.
And now, have fun trying sorts in Calc!
Licence information: The macro is free and cost-free to use for personal and
non-commercial use. Other uses upon request to the author.
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]