Jump to content

[Array Sort Date] Why is it so difficult?


Crayfish
 Share

Recommended Posts

I have tried everything to sort dates within an array. It's always sort incorrectly.

I have tried compare $1 < $2 or $1>$2 and shift the order down the row but that doesn't help when there a date down the list still wrong.

Anyone has any suggestion or logic - please point me to the right direction.

Here is a quick example to test.

Thank you in advance.

SOLVED EXAMPLE - By Malkey

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>
#include <WindowsConstants.au3>

Opt("GUIOnEventMode", 1) ; 1 = enable.
Opt("GUICloseOnESC", 1) ; 1 = Send the $GUI_EVENT_CLOSE message when ESC is pressed (default).
Opt('MustDeclareVars', 1)
Global $hListView

_Example1()

While 1
    Sleep(100)
WEnd


Func _Example1()
    ;Local $hImage
    Local $iExWindowStyle = BitOR($WS_EX_DLGMODALFRAME, $WS_EX_CLIENTEDGE)
    Local $iExListViewStyle = BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_GRIDLINES, $LVS_EX_DOUBLEBUFFER)
    GUICreate("ListView Sort", 300, 400)
    GUISetOnEvent($GUI_EVENT_CLOSE, "CloseGUI")
    $hListView = GUICtrlCreateListView("Column1|Column2|Column3|Col4", 10, 10, 280, 380, -1, $iExWindowStyle)
    _GUICtrlListView_SetExtendedListViewStyle($hListView, $iExListViewStyle)
    GUICtrlSetOnEvent($hListView, "sort")

    _AddRow($hListView, "10/20/2001|2|7|10/14/2012")
    _AddRow($hListView, "12/15/2000|1|8|5/22/2012")
    _AddRow($hListView, "04/05/2004|----|----|----")
    _AddRow($hListView, "1/22/2004|4|6|1/4/2012")
    _AddRow($hListView, "11/05/2005|5|3|10/12/2012")
    _AddRow($hListView, "8/15/2004|6|2|10/10/2010")
    _AddRow($hListView, "10/05/2008|7||11/11/2011")
    _AddRow($hListView, "11/05/2012|8|4|05/15/2005")
    _AddRow($hListView, "12/05/2012|9|5|1/21/2004")
    GUISetState()
    _GUICtrlListView_RegisterSortCallBack($hListView)
EndFunc   ;==>_Example1

Func sort()
    Local $iCol = GUICtrlGetState($hListView)
    Local $iRowCount = _GUICtrlListView_GetItemCount(ControlGetHandle("ListView Sort", "", $hListView))

    ; ----- If the column clicked contains date formated "MM/DD/YYYY" in the first, middle, or last
    ;      row, then convert to date format "YYYY/MM/DD" ----
    If StringRegExp(_GUICtrlListView_GetItemText($hListView, 0, $iCol), "(d{1,2})[/.-](d{1,2})[/.-](d{4})") Or _
            StringRegExp(_GUICtrlListView_GetItemText($hListView, $iRowCount - 1, $iCol), "(d{1,2})[/.-](d{1,2})[/.-](d{4})") Or _
            StringRegExp(_GUICtrlListView_GetItemText($hListView, Int($iRowCount / 2), $iCol), "(d{1,2})[/.-](d{1,2})[/.-](d{4})") Then
        Local $aItem2D[$iRowCount][2], $aTemp

        For $i = 0 To $iRowCount - 1
            $aItem2D[$i][0] = _GUICtrlListView_GetItemText($hListView, $i, $iCol)
            If StringRegExp($aItem2D[$i][0], "(d{1,2})[/.-](d{1,2})[/.-](d{4})") Then
                $aTemp = StringRegExp($aItem2D[$i][0], "(d+)", 3)
                $aItem2D[$i][1] = StringFormat("%4d/%02d/%02d", $aTemp[2], $aTemp[0], $aTemp[1])
                _GUICtrlListView_SetItem($hListView, $aItem2D[$i][1], $i, $iCol)
            Else
                $aItem2D[$i][1] = $aItem2D[$i][0]
                _GUICtrlListView_SetItem($hListView, $aItem2D[$i][1], $i, $iCol)
            EndIf
            ;ConsoleWrite($aItem2D[$i][0] & "  " & $aItem2D[$i][1] & @LF)
        Next
        ;ConsoleWrite(@LF)

        ; -------- Sort all columns ----------
        _GUICtrlListView_SortItems($hListView, $iCol)

        ; -------- Convert date format "YYYY/MM/DD" back to the original format --------
        For $i = 0 To $iRowCount - 1
            For $j = 0 To $iRowCount - 1
                If StringCompare(_GUICtrlListView_GetItemText($hListView, $i, $iCol), $aItem2D[$j][1]) = 0 Then
                    _GUICtrlListView_SetItem($hListView, $aItem2D[$j][0], $i, $iCol)
                    ExitLoop 1
                EndIf
            Next
        Next
    Else
        _GUICtrlListView_SortItems($hListView, $iCol)
    EndIf
EndFunc   ;==>sort

Func _AddRow($hWnd, $sItem)
    Local $aItem = StringSplit($sItem, "|"), $iColWidth
    Local $iIndex = _GUICtrlListView_AddItem($hWnd, $aItem[1], -1, _GUICtrlListView_GetItemCount($hWnd))
    _GUICtrlListView_SetColumnWidth($hWnd, 0, $LVSCW_AUTOSIZE_USEHEADER)
    For $x = 2 To $aItem[0]
        _GUICtrlListView_AddSubItem($hWnd, $iIndex, $aItem[$x], $x - 1)
        _GUICtrlListView_SetColumnWidth($hWnd, $x - 1, $LVSCW_AUTOSIZE)
        $iColWidth = _GUICtrlListView_GetColumnWidth($hWnd, $x - 1)
        _GUICtrlListView_SetColumnWidth($hWnd, $x - 1, $LVSCW_AUTOSIZE_USEHEADER)
        If $iColWidth > _GUICtrlListView_GetColumnWidth($hWnd, $x - 1) Then
            _GUICtrlListView_SetColumnWidth($hWnd, $x - 1, $LVSCW_AUTOSIZE)
        EndIf
    Next
EndFunc   ;==>_AddRow

Func CloseGUI()
    _GUICtrlListView_UnRegisterSortCallBack($hListView)
    GUIDelete()
    Exit
EndFunc   ;==>CloseGUI
Edited by Crayfish
Link to comment
Share on other sites

it's gotta be sorting by a string. Why not do the sort prior to the _addrow, so you can more easily compare...example:

#include <Array.au3>

Dim $array[3][2]=[["10/01/2012",""], ["05/10/2011",""], ["01/12/2012",""]]

for $i = 0 to UBound ( $array ) - 1
$array[$i][1] = Int(StringRegExpReplace ( $array[$i][0], "(d*)/(d*)/(d*)", "$3$1$2" ))
Next
_ArrayDisplay ( $array,"no sort" )

 
_ArraySort ( $array,False,0,0,1 )
_ArrayDisplay ( $array,"sort by date asc (as integer)" )

_ArraySort ( $array,False,0,0,0 )
_ArrayDisplay ( $array,"sort by date asc (as string)" )
Edited by jdelaney
IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.
Link to comment
Share on other sites

I can't do that with a 2D arrays it will mess up the order in relation with.

Any other idea?

it's gotta be sorting by a string. Why not do the sort prior to the _addrow, so you can more easily compare...example:

#include <Array.au3>

Dim $array[3][2]=[["10/01/2012",""], ["05/10/2011",""], ["01/12/2012",""]]

for $i = 0 to UBound ( $array ) - 1
$array[$i][1] = Int(StringRegExpReplace ( $array[$i][0], "(d*)/(d*)/(d*)", "$3$1$2" ))
Next
_ArrayDisplay ( $array,"no sort" )


_ArraySort ( $array,False,0,0,1 )
_ArrayDisplay ( $array,"sort by date asc (as integer)" )

_ArraySort ( $array,False,0,0,0 )
_ArrayDisplay ( $array,"sort by date asc (as string)" )

Link to comment
Share on other sites

The easy solution would be to have the date in format @year/@month/@day.

_AddRow($hListView, "2001/10/20", $aIcons)
    _AddRow($hListView, "2000/12/15", $aIcons)
    _AddRow($hListView, "2004/04/05", $aIcons)
    _AddRow($hListView, "2004/01/22", $aIcons)
    _AddRow($hListView, "2005/11/05", $aIcons)
    _AddRow($hListView, "2004/08/15", $aIcons)
    _AddRow($hListView, "2008/10/05", $aIcons)
    _AddRow($hListView, "2012/11/05", $aIcons)
    _AddRow($hListView, "2012/12/05", $aIcons)

Another way would be to have a 2D array, column 1 showing the data as you want to have it displayed, column 2 again in format @year/@month/@day, but this time only used for sorting the array and not being displayed.

Link to comment
Share on other sites

Like he said.

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>
#include <WindowsConstants.au3>
Opt("GUIOnEventMode", 1) ; 1 = enable.
Opt("GUICloseOnESC", 1) ; 1 = Send the $GUI_EVENT_CLOSE message when ESC is pressed (default).
Opt('MustDeclareVars', 1)
Global $hListView, $hListView2
_Example1()
While 1
    Sleep(3000)
WEnd
Func _Example1()
    Local $hImage, $aIcons[3] = [0, 3, 6]
    Local $iExWindowStyle = BitOR($WS_EX_DLGMODALFRAME, $WS_EX_CLIENTEDGE)
    Local $iExListViewStyle = BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_SUBITEMIMAGES, $LVS_EX_GRIDLINES, $LVS_EX_CHECKBOXES, $LVS_EX_DOUBLEBUFFER)
    GUICreate("ListView Sort", 300, 400)
    GUISetOnEvent($GUI_EVENT_CLOSE, "CloseGUI")
    $hListView = GUICtrlCreateListView("Column1", 10, 10, 280, 380, -1, $iExWindowStyle)
    _GUICtrlListView_SetExtendedListViewStyle($hListView, $iExListViewStyle)
    GUICtrlSetOnEvent($hListView, "sort")
    ; Load images
    $hImage = _GUIImageList_Create(18, 18, 5, 3)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -7)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -12)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -3)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -4)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -5)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -6)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -9)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -10)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -11)
    _GUICtrlListView_SetImageList($hListView, $hImage, 1)
    _AddRow($hListView, "10/20/2001", $aIcons)
    GUISetState()
    _GUICtrlListView_RegisterSortCallBack($hListView)
    _AddRow($hListView, "12/15/2000", $aIcons)
    _AddRow($hListView, "04/05/2004", $aIcons)
    _AddRow($hListView, "1/22/2004", $aIcons)
    _AddRow($hListView, "11/05/2005", $aIcons)
    _AddRow($hListView, "8/15/2004", $aIcons)
    _AddRow($hListView, "10/05/2008", $aIcons)
    _AddRow($hListView, "11/05/2012", $aIcons)
    _AddRow($hListView, "12/05/2012", $aIcons)

    ; ---------------- Sort ------------------------
    Local $iCount = _GUICtrlListView_GetItemCount(ControlGetHandle("ListView Sort", "", $hListView))
    Local $aItem2D[$iCount][2], $aTemp
    For $i = 0 To $iCount - 1
        $aItem2D[$i][0] = _GUICtrlListView_GetItemText($hListView, $i)
        $aTemp = StringRegExp($aItem2D[$i][0], "(d+)", 3)
        $aItem2D[$i][1] = StringFormat("%4d/%02d/%02d", $aTemp[2], $aTemp[0], $aTemp[1])
    Next
    _ArraySort($aItem2D, 1, 0, 0, 1)
    For $i = 0 To $iCount - 1
        _GUICtrlListView_SetItem($hListView, $aItem2D[$i][0], $i)
    Next
    ; ------------ End of Sort ------------------------

EndFunc   ;==>_Example1
Func sort()
    _GUICtrlListView_SortItems($hListView, GUICtrlGetState($hListView))
EndFunc   ;==>sort
Func _AddRow($hWnd, $sItem, $aIcons, $iPlus = 0)
    Local $aItem = StringSplit($sItem, "|")
    Local $iIndex = _GUICtrlListView_AddItem($hWnd, $aItem[1], $aIcons[0] + $iPlus, _GUICtrlListView_GetItemCount($hWnd) + 9999)
    _GUICtrlListView_SetColumnWidth($hWnd, 0, $LVSCW_AUTOSIZE_USEHEADER)
    For $x = 2 To $aItem[0]
        _GUICtrlListView_AddSubItem($hWnd, $iIndex, $aItem[$x], $x - 1, $aIcons[$x - 1] + $iPlus)
        _GUICtrlListView_SetColumnWidth($hWnd, $x - 1, $LVSCW_AUTOSIZE)
    Next
EndFunc   ;==>_AddRow
Func CloseGUI()
    _GUICtrlListView_UnRegisterSortCallBack($hListView)
    GUIDelete()
    Exit
EndFunc   ;==>CloseGUI
Link to comment
Share on other sites

KaFu: I never knew about hidden column with GuiLV - I will look up regard this. Might be the only way to resolve this. It's not possible for me to use European date format.

Malkey: Your function work for 1D array Is there a way to keep the relationship with 2D array?

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>
#include <WindowsConstants.au3>
Opt("GUIOnEventMode", 1) ; 1 = enable.
Opt("GUICloseOnESC", 1) ; 1 = Send the $GUI_EVENT_CLOSE message when ESC is pressed (default).
Opt('MustDeclareVars', 1)
Global $hListView
_Example1()
While 1
Sleep(3000)
WEnd
Func _Example1()
Local $hImage, $aIcons[3] = [0, 3, 6]
Local $iExWindowStyle = BitOR($WS_EX_DLGMODALFRAME, $WS_EX_CLIENTEDGE)
Local $iExListViewStyle = BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_SUBITEMIMAGES, $LVS_EX_GRIDLINES, $LVS_EX_CHECKBOXES, $LVS_EX_DOUBLEBUFFER)
GUICreate("ListView Sort", 300, 400)
GUISetOnEvent($GUI_EVENT_CLOSE, "CloseGUI")
$hListView = GUICtrlCreateListView("Column1|Column2", 10, 10, 280, 380, -1, $iExWindowStyle)
_GUICtrlListView_SetExtendedListViewStyle($hListView, $iExListViewStyle)
GUICtrlSetOnEvent($hListView, "sort")
; Load images
$hImage = _GUIImageList_Create(18, 18, 5, 3)
_GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -7)
_GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -12)
_GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -3)
_GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -4)
_GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -5)
_GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -6)
_GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -9)
_GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -10)
_GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -11)
_GUICtrlListView_SetImageList($hListView, $hImage, 1)
_AddRow($hListView, "10/20/2001|2", $aIcons)
GUISetState()
_GUICtrlListView_RegisterSortCallBack($hListView)
_AddRow($hListView, "12/15/2000|1", $aIcons)
_AddRow($hListView, "04/05/2004|3", $aIcons)
_AddRow($hListView, "1/22/2004|4", $aIcons)
_AddRow($hListView, "11/05/2005|5", $aIcons)
_AddRow($hListView, "8/15/2004|6", $aIcons)
_AddRow($hListView, "10/05/2008|7", $aIcons)
_AddRow($hListView, "11/05/2012|8", $aIcons)
_AddRow($hListView, "12/05/2012|9", $aIcons)

; ---------------- Sort ------------------------
Local $iCount = _GUICtrlListView_GetItemCount(ControlGetHandle("ListView Sort", "", $hListView))
Local $aItem2D[$iCount][2], $aTemp
For $i = 0 To $iCount - 1
     $aItem2D[$i][0] = _GUICtrlListView_GetItemText($hListView, $i)
     $aTemp = StringRegExp($aItem2D[$i][0], "(d+)", 3)
     $aItem2D[$i][1] = StringFormat("%4d/%02d/%02d", $aTemp[2], $aTemp[0], $aTemp[1])
Next
_ArraySort($aItem2D, 1, 0, 0, 1)
For $i = 0 To $iCount - 1
     _GUICtrlListView_SetItem($hListView, $aItem2D[$i][0], $i)
Next
; ------------ End of Sort ------------------------

EndFunc ;==>_Example1
Func sort()
_GUICtrlListView_SortItems($hListView, GUICtrlGetState($hListView))
EndFunc ;==>sort
Func _AddRow($hWnd, $sItem, $aIcons, $iPlus = 0)
Local $aItem = StringSplit($sItem, "|")
Local $iIndex = _GUICtrlListView_AddItem($hWnd, $aItem[1], $aIcons[0] + $iPlus, _GUICtrlListView_GetItemCount($hWnd) + 9999)
_GUICtrlListView_SetColumnWidth($hWnd, 0, $LVSCW_AUTOSIZE_USEHEADER)
For $x = 2 To $aItem[0]
     _GUICtrlListView_AddSubItem($hWnd, $iIndex, $aItem[$x], $x - 1, $aIcons[$x - 1] + $iPlus)
     _GUICtrlListView_SetColumnWidth($hWnd, $x - 1, $LVSCW_AUTOSIZE)
Next
EndFunc ;==>_AddRow
Func CloseGUI()
_GUICtrlListView_UnRegisterSortCallBack($hListView)
GUIDelete()
Exit
EndFunc ;==>CloseGUI
Edited by Crayfish
Link to comment
Share on other sites

Hidden column seem too much work.

I have taken all your good ideas jdelaney, kafu, malkey and combined to reverse the date temporarily to sort and put it back.

Here is the result. Seem to work except 1 problem _ Check the array I put TEST and see March still fall short of April due to leading '0'. Any suggestion? Another string parsing for date consistency?

How would I go about filter this date range to show only specific range - from/to before/after?

Semi Functional Resolution:

#include <Array.au3>

SORT()

Func SORT()
    ;===============================================================================
    ; Stubborn Date Sort
    ;===============================================================================
    Local $avArray[11][5]= _
    [["03/04/2010","03","04","20","10"], _
     ["04/01/2011","04","01","20","11"], _
     ["03/05/2010","03","05","20","10"], _
     ["02/30/2012","02","30","20","12"], _
     ["1/1/2001","1","1","20","01"], _
     ["04/02/2011","04","02","20","11"], _
     ["02/7/2011","02","7","20","11"], _
     ["03/06/2010","03","06","20","10"], _
     ["04/31/2007","04","31","20","07"], _
     ["3/31/2007","TEST","TEST","TEST","TEST"], _
     ["04/03/2011","04","03","20","11"]]

    _ArrayDisplay($avArray)
    For $i = 0 To UBound($avArray,1) - 1
        $avArray[$i][0] = _YMD($avArray[$i][0])
    Next
    _ArraySort($avArray)
    For $i = 0 To UBound($avArray,1) - 1
        $avArray[$i][0] = _MDY($avArray[$i][0])
    Next
    _ArrayDisplay($avArray)
EndFunc

Func _MDY($sDate) ; YYYY/MM/DD >> MM/DD/YYYY
        Return StringRegExpReplace ( $sDate, "(d*)/(d*)/(d*)", "$2/$3/$1" )
EndFunc

Func _YMD($sDate) ; MM/DD/YYYY >> YYYY/MM/DD
        Return StringRegExpReplace ( $sDate, "(d*)/(d*)/(d*)", "$3/$1/$2" )
EndFunc

The easy solution would be to have the date in format @year/@month/@day.

_AddRow($hListView, "2001/10/20", $aIcons)
_AddRow($hListView, "2000/12/15", $aIcons)
_AddRow($hListView, "2004/04/05", $aIcons)
_AddRow($hListView, "2004/01/22", $aIcons)
_AddRow($hListView, "2005/11/05", $aIcons)
_AddRow($hListView, "2004/08/15", $aIcons)
_AddRow($hListView, "2008/10/05", $aIcons)
_AddRow($hListView, "2012/11/05", $aIcons)
_AddRow($hListView, "2012/12/05", $aIcons)

Another way would be to have a 2D array, column 1 showing the data as you want to have it displayed, column 2 again in format @year/@month/@day, but this time only used for sorting the array and not being displayed.

Edited by Crayfish
Link to comment
Share on other sites

I was faced with a similar problem parsing ugly SAP date output. I chopped the string into pieces, used _DateDiff('s', "1970/01/01 00:00:00", $temp2[3] & "/" & $temp2[1] & "/" & $temp2[2] & " 00:00:00") to generate epoch time in place of the string, sorted on the epoch time and turned that back into a readable date with _DateAdd('s', $result, "1970/01/01 00:00:00")

Above, $temp is the array representing the SAP date blown apart on "/" and rearragned. $result is the result of sorting the array and using _ArrayPop to retrieve the date I wanted. In this case, it was the largest epoch time, i.e. furthest in the future.

.

I had to trim the HH:MM:SS off the end, but that's a simple StringTrim.

Link to comment
Share on other sites

This example works on 2d arrays.

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>
#include <WindowsConstants.au3>

Opt("GUIOnEventMode", 1) ; 1 = enable.
Opt("GUICloseOnESC", 1) ; 1 = Send the $GUI_EVENT_CLOSE message when ESC is pressed (default).
Opt('MustDeclareVars', 1)
Global $hListView

_Example1()

While 1
    Sleep(3000)
WEnd


Func _Example1()
    Local $hImage, $aIcons[3] = [0, 3, 6]
    Local $iExWindowStyle = BitOR($WS_EX_DLGMODALFRAME, $WS_EX_CLIENTEDGE)
    Local $iExListViewStyle = BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_SUBITEMIMAGES, $LVS_EX_GRIDLINES, $LVS_EX_CHECKBOXES, $LVS_EX_DOUBLEBUFFER)
    GUICreate("ListView Sort", 300, 400)
    GUISetOnEvent($GUI_EVENT_CLOSE, "CloseGUI")
    $hListView = GUICtrlCreateListView("Column1|Column2", 10, 10, 280, 380, -1, $iExWindowStyle)
    _GUICtrlListView_SetExtendedListViewStyle($hListView, $iExListViewStyle)
    GUICtrlSetOnEvent($hListView, "sort")
    ; Load images
    $hImage = _GUIImageList_Create(18, 18, 5, 3)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -7)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -12)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -3)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -4)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -5)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -6)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -9)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -10)
    _GUIImageList_AddIcon($hImage, @SystemDir & "shell32.dll", -11)
    _GUICtrlListView_SetImageList($hListView, $hImage, 1)
    _AddRow($hListView, "10/20/2001|2", $aIcons)
    _AddRow($hListView, "12/15/2000|1", $aIcons)
    _AddRow($hListView, "04/05/2004|3", $aIcons)
    _AddRow($hListView, "1/22/2004|4", $aIcons)
    _AddRow($hListView, "11/05/2005|5", $aIcons)
    _AddRow($hListView, "8/15/2004|6", $aIcons)
    _AddRow($hListView, "10/05/2008|7", $aIcons)
    _AddRow($hListView, "11/05/2012|8", $aIcons)
    _AddRow($hListView, "12/05/2012|9", $aIcons)
    GUISetState()
    _GUICtrlListView_RegisterSortCallBack($hListView)
EndFunc   ;==>_Example1

Func sort()
    Local $iCol = GUICtrlGetState($hListView)

    ; ----- If the column clicked contains date formated "MM/DD/YYYY" then convert to date format "YYYY/MM/DD" ----
    If StringRegExp(_GUICtrlListView_GetItemText($hListView, 0, $iCol), "(d{2})[/.-](d{2})[/.-](d{4})") Then
        Local $iRowCount = _GUICtrlListView_GetItemCount(ControlGetHandle("ListView Sort", "", $hListView))
        Local $aItem2D[$iRowCount][2], $aTemp

        For $i = 0 To $iRowCount - 1
            $aItem2D[$i][0] = _GUICtrlListView_GetItemText($hListView, $i, $iCol)
            $aTemp = StringRegExp($aItem2D[$i][0], "(d+)", 3)
            $aItem2D[$i][1] = StringFormat("%4d/%02d/%02d", $aTemp[2], $aTemp[0], $aTemp[1])
            _GUICtrlListView_SetItem($hListView, $aItem2D[$i][1], $i, $iCol)
        Next

        ; -------- Sort all columns ----------
        _GUICtrlListView_SortItems($hListView, $iCol)

        ; -------- Convert date format "YYYY/MM/DD" back to the original format --------
        For $i = 0 To $iRowCount - 1
            For $j = 0 To $iRowCount - 1
                If StringCompare(_GUICtrlListView_GetItemText($hListView, $i, $iCol), $aItem2D[$j][1]) = 0 Then
                    _GUICtrlListView_SetItem($hListView, $aItem2D[$j][0], $i, $iCol)
                    ExitLoop 1
                EndIf
            Next
        Next
    Else
        _GUICtrlListView_SortItems($hListView, $iCol)
    EndIf
EndFunc   ;==>sort

Func _AddRow($hWnd, $sItem, $aIcons, $iPlus = 0)
    Local $aItem = StringSplit($sItem, "|")
    Local $iIndex = _GUICtrlListView_AddItem($hWnd, $aItem[1], $aIcons[0] + $iPlus, _GUICtrlListView_GetItemCount($hWnd) + 9999)
    _GUICtrlListView_SetColumnWidth($hWnd, 0, $LVSCW_AUTOSIZE_USEHEADER)
    For $x = 2 To $aItem[0]
        _GUICtrlListView_AddSubItem($hWnd, $iIndex, $aItem[$x], $x - 1, $aIcons[$x - 1] + $iPlus)
        _GUICtrlListView_SetColumnWidth($hWnd, $x - 1, $LVSCW_AUTOSIZE)
    Next
EndFunc   ;==>_AddRow

Func CloseGUI()
    _GUICtrlListView_UnRegisterSortCallBack($hListView)
    GUIDelete()
    Exit
EndFunc   ;==>CloseGUI

Edit: "the" should have been "then".

Edited by Malkey
Link to comment
Share on other sites

Why not use _DateToDayValue to convert dates for the sort column - it doesn't mind one digit months or days or I'm I missing something here?

Jury: Thank you for trying but your humble idea my bad attempt. Needless to say I did took it into consideration and tried it out. See it for yourself.

_DayValueToDate value back to date no longer hold it integrity and original date and estimate Gregorian date is no longer match.

Make mistake on my part for rushing. Seems to work ok when I tried again.

#include <Date.au3>
#include <Array.au3>

SORT()

Func SORT()
    ;===============================================================================
    ; Stubborn Date Sort
    ;===============================================================================
    Local $avArray[11][5]= _
    [["3/04/2010","03","04","20","10"], _
     ["04/1/2011","04","01","20","11"], _
     ["03/05/2010","03","05","20","10"], _
     ["2/30/2012","02","30","20","12"], _
     ["1/1/2001","1","1","20","01"], _
     ["04/2/2011","04","02","20","11"], _
     ["02/7/2011","02","7","20","11"], _
     ["03/06/2010","03","06","20","10"], _
     ["04/31/2007","04","31","20","07"], _
     ["3/31/2007","TEST","TEST","TEST","TEST"], _
     ["04/03/2011","04","03","20","11"]]
    Local $DMYHolder
    Local $Y, $M, $D

    _ArrayDisplay($avArray)
    For $i = 0 To UBound($avArray,1) - 1
        $DMYHolder = _DateToDayValueArray($avArray[$i][0])
        $avArray[$i][0] = _DateToDayValue($DMYHolder[3],$DMYHolder[1],$DMYHolder[2])
    Next
    _ArraySort($avArray)
    For $i = 0 To UBound($avArray,1) - 1
        $avArray[$i][0] = _DayValueToDate($avArray[$i][0], $Y, $M, $D)
    Next
    _ArrayDisplay($avArray)
EndFunc

Func _DateToDayValueArray($sDate) ;Turn date into array
    Local $TimeArray = StringSplit ( $sDate, "/" )
    Return $TimeArray
EndFunc

Malkey: Thank you I tried that but it seems to tripping out with me and sort seems to not work as intended.

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>
#include <WindowsConstants.au3>

Opt("GUIOnEventMode", 1) ; 1 = enable.
Opt("GUICloseOnESC", 1) ; 1 = Send the $GUI_EVENT_CLOSE message when ESC is pressed (default).
Opt('MustDeclareVars', 1)
Global $hListView

_Example1()

While 1
Sleep(3000)
WEnd


Func _Example1()
GUICreate("ListView Sort", 300, 400)
GUISetOnEvent($GUI_EVENT_CLOSE, "CloseGUI")
$hListView = GUICtrlCreateListView("DATE|INC1|INC2|INC3|INC4", 10, 10, 280, 380)
GUICtrlSetOnEvent($hListView, "sort")

_AddRow($hListView, "03/04/2010|03|04|20|10")
_AddRow($hListView, "04/01/2011|04|01|20|11")
_AddRow($hListView, "1/1/2001|1|1|20|01")
_AddRow($hListView, "02/30/2012|02|30|20|12")
_AddRow($hListView, "04/02/2011|04|02|20|11")
_AddRow($hListView, "02/7/2011|02|7|20|11")
_AddRow($hListView, "04/31/2007|04|31|20|07")
_AddRow($hListView, "3/31/2007|----|----|----|----")
_AddRow($hListView, "04/03/2011|04|03|20|11")
GUISetState()

_GUICtrlListView_RegisterSortCallBack($hListView)
EndFunc ;==>_Example1

Func sort()
Local $iCol = GUICtrlGetState($hListView)

; ----- If the column clicked contains date formated "MM/DD/YYYY" then convert to date format "YYYY/MM/DD" ----
If StringRegExp(_GUICtrlListView_GetItemText($hListView, 0, $iCol), "(d{2})[/.-](d{2})[/.-](d{4})") Then
     Local $iRowCount = _GUICtrlListView_GetItemCount(ControlGetHandle("ListView Sort", "", $hListView))
     Local $aItem2D[$iRowCount][2], $aTemp

     For $i = 0 To $iRowCount - 1
         $aItem2D[$i][0] = _GUICtrlListView_GetItemText($hListView, $i, $iCol)
         $aTemp = StringRegExp($aItem2D[$i][0], "(d+)", 3)
         $aItem2D[$i][1] = StringFormat("%4d/%02d/%02d", $aTemp[2], $aTemp[0], $aTemp[1])
         _GUICtrlListView_SetItem($hListView, $aItem2D[$i][1], $i, $iCol)
     Next

     ; -------- Sort all columns ----------
     _GUICtrlListView_SortItems($hListView, $iCol)

     ; -------- Convert date format "YYYY/MM/DD" back to the original format --------
     For $i = 0 To $iRowCount - 1
         For $j = 0 To $iRowCount - 1
             If StringCompare(_GUICtrlListView_GetItemText($hListView, $i, $iCol), $aItem2D[$j][1]) = 0 Then
                 _GUICtrlListView_SetItem($hListView, $aItem2D[$j][0], $i, $iCol)
                 ExitLoop 1
             EndIf
         Next
     Next
Else
     _GUICtrlListView_SortItems($hListView, $iCol)
EndIf
EndFunc ;==>sort

Func _AddRow($hWnd, $sItem)
Local $aItem = StringSplit($sItem, "|")
Local $iIndex = _GUICtrlListView_AddItem($hWnd, $aItem[1])
For $x = 2 To $aItem[0]
     _GUICtrlListView_AddSubItem($hWnd, $iIndex, $aItem[$x], $x - 1)
     _GUICtrlListView_SetColumnWidth($hWnd, $x - 1, $LVSCW_AUTOSIZE)
Next
EndFunc ;==>_AddRow

Func CloseGUI()
_GUICtrlListView_UnRegisterSortCallBack($hListView)
GUIDelete()
Exit
EndFunc ;==>CloseGUI
Edited by Crayfish
Link to comment
Share on other sites

A better example that sorts a list view by the column that is clicked on that column's header. The column sorts acsending and decending with each click.

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>
#include <WindowsConstants.au3>

Opt("GUIOnEventMode", 1) ; 1 = enable.
Opt("GUICloseOnESC", 1) ; 1 = Send the $GUI_EVENT_CLOSE message when ESC is pressed (default).
Opt('MustDeclareVars', 1)
Global $hListView

_Example1()

While 1
    Sleep(100)
WEnd


Func _Example1()
    ;Local $hImage
    Local $iExWindowStyle = BitOR($WS_EX_DLGMODALFRAME, $WS_EX_CLIENTEDGE)
    Local $iExListViewStyle = BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_GRIDLINES, $LVS_EX_DOUBLEBUFFER)
    GUICreate("ListView Sort", 300, 400)
    GUISetOnEvent($GUI_EVENT_CLOSE, "CloseGUI")
    $hListView = GUICtrlCreateListView("Column1|Column2|Column3|Col4", 10, 10, 280, 380, -1, $iExWindowStyle)
    _GUICtrlListView_SetExtendedListViewStyle($hListView, $iExListViewStyle)
    GUICtrlSetOnEvent($hListView, "sort")

    _AddRow($hListView, "10/20/2001|2|7|10/14/2012")
    _AddRow($hListView, "12/15/2000|1|8|5/22/2012")
    _AddRow($hListView, "04/05/2004|----|----|----")
    _AddRow($hListView, "1/22/2004|4|6|1/4/2012")
    _AddRow($hListView, "11/05/2005|5|3|10/12/2012")
    _AddRow($hListView, "8/15/2004|6|2|10/10/2010")
    _AddRow($hListView, "10/05/2008|7||11/11/2011")
    _AddRow($hListView, "11/05/2012|8|4|05/15/2005")
    _AddRow($hListView, "12/05/2012|9|5|1/21/2004")
    GUISetState()
    _GUICtrlListView_RegisterSortCallBack($hListView)
EndFunc   ;==>_Example1

Func sort()
    Local $iCol = GUICtrlGetState($hListView)
    Local $iRowCount = _GUICtrlListView_GetItemCount(ControlGetHandle("ListView Sort", "", $hListView))

    ; ----- If the column clicked contains date formated "MM/DD/YYYY" in the first, middle, or last
    ;      row, then convert to date format "YYYY/MM/DD" ----
    If StringRegExp(_GUICtrlListView_GetItemText($hListView, 0, $iCol), "(d{1,2})[/.-](d{1,2})[/.-](d{4})") Or _
            StringRegExp(_GUICtrlListView_GetItemText($hListView, $iRowCount - 1, $iCol), "(d{1,2})[/.-](d{1,2})[/.-](d{4})") Or _
            StringRegExp(_GUICtrlListView_GetItemText($hListView, Int($iRowCount / 2), $iCol), "(d{1,2})[/.-](d{1,2})[/.-](d{4})") Then
        Local $aItem2D[$iRowCount][2], $aTemp

        For $i = 0 To $iRowCount - 1
            $aItem2D[$i][0] = _GUICtrlListView_GetItemText($hListView, $i, $iCol)
            If StringRegExp($aItem2D[$i][0], "(d{1,2})[/.-](d{1,2})[/.-](d{4})") Then
                $aTemp = StringRegExp($aItem2D[$i][0], "(d+)", 3)
                $aItem2D[$i][1] = StringFormat("%4d/%02d/%02d", $aTemp[2], $aTemp[0], $aTemp[1])
                _GUICtrlListView_SetItem($hListView, $aItem2D[$i][1], $i, $iCol)
            Else
                $aItem2D[$i][1] = $aItem2D[$i][0]
                _GUICtrlListView_SetItem($hListView, $aItem2D[$i][1], $i, $iCol)
            EndIf
            ;ConsoleWrite($aItem2D[$i][0] & "  " & $aItem2D[$i][1] & @LF)
        Next
        ;ConsoleWrite(@LF)

        ; -------- Sort all columns ----------
        _GUICtrlListView_SortItems($hListView, $iCol)

        ; -------- Convert date format "YYYY/MM/DD" back to the original format --------
        For $i = 0 To $iRowCount - 1
            For $j = 0 To $iRowCount - 1
                If StringCompare(_GUICtrlListView_GetItemText($hListView, $i, $iCol), $aItem2D[$j][1]) = 0 Then
                    _GUICtrlListView_SetItem($hListView, $aItem2D[$j][0], $i, $iCol)
                    ExitLoop 1
                EndIf
            Next
        Next
    Else
        _GUICtrlListView_SortItems($hListView, $iCol)
    EndIf
EndFunc   ;==>sort

Func _AddRow($hWnd, $sItem)
    Local $aItem = StringSplit($sItem, "|"), $iColWidth
    Local $iIndex = _GUICtrlListView_AddItem($hWnd, $aItem[1], -1, _GUICtrlListView_GetItemCount($hWnd))
    _GUICtrlListView_SetColumnWidth($hWnd, 0, $LVSCW_AUTOSIZE_USEHEADER)
    For $x = 2 To $aItem[0]
        _GUICtrlListView_AddSubItem($hWnd, $iIndex, $aItem[$x], $x - 1)
        _GUICtrlListView_SetColumnWidth($hWnd, $x - 1, $LVSCW_AUTOSIZE)
        $iColWidth = _GUICtrlListView_GetColumnWidth($hWnd, $x - 1)
        _GUICtrlListView_SetColumnWidth($hWnd, $x - 1, $LVSCW_AUTOSIZE_USEHEADER)
        If $iColWidth > _GUICtrlListView_GetColumnWidth($hWnd, $x - 1) Then
            _GUICtrlListView_SetColumnWidth($hWnd, $x - 1, $LVSCW_AUTOSIZE)
        EndIf
    Next
EndFunc   ;==>_AddRow

Func CloseGUI()
    _GUICtrlListView_UnRegisterSortCallBack($hListView)
    GUIDelete()
    Exit
EndFunc   ;==>CloseGUI
Link to comment
Share on other sites

Try this:

You pass in a compare function name string as param

The example just uses StringCompare() as a test. Just put whatever comparison you want in that function. The comparison must return -1 0 or 1 to indicate the relationship between the 2 items. See StringCompare() help for details. But it's the same gimmick used in C libraries for years for QSort. You pass in a function pointer. In this case AutoIt passes functions by name string.

Edited by MilesAhead
Link to comment
Share on other sites

Malkey - Excellent work Malkey and thank you for continuing assist. I never knew how something so simple as sorting date can turn out to be so tripping.

I really love your simplistic date parse sort comparation. This is very useful to compare array dates. You should promote this into a mini snippet or UDF and I know it will assist million people.

MilesAhead - That's seem to do a lot of overhead no?

A better example that sorts a list view by the column that is clicked on that column's header. The column sorts acsending and decending with each click.

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>
#include <WindowsConstants.au3>

Opt("GUIOnEventMode", 1) ; 1 = enable.
Opt("GUICloseOnESC", 1) ; 1 = Send the $GUI_EVENT_CLOSE message when ESC is pressed (default).
Opt('MustDeclareVars', 1)
Global $hListView

_Example1()

While 1
Sleep(100)
WEnd


Func _Example1()
;Local $hImage
Local $iExWindowStyle = BitOR($WS_EX_DLGMODALFRAME, $WS_EX_CLIENTEDGE)
Local $iExListViewStyle = BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_GRIDLINES, $LVS_EX_DOUBLEBUFFER)
GUICreate("ListView Sort", 300, 400)
GUISetOnEvent($GUI_EVENT_CLOSE, "CloseGUI")
$hListView = GUICtrlCreateListView("Column1|Column2|Column3|Col4", 10, 10, 280, 380, -1, $iExWindowStyle)
_GUICtrlListView_SetExtendedListViewStyle($hListView, $iExListViewStyle)
GUICtrlSetOnEvent($hListView, "sort")

_AddRow($hListView, "10/20/2001|2|7|10/14/2012")
_AddRow($hListView, "12/15/2000|1|8|5/22/2012")
_AddRow($hListView, "04/05/2004|----|----|----")
_AddRow($hListView, "1/22/2004|4|6|1/4/2012")
_AddRow($hListView, "11/05/2005|5|3|10/12/2012")
_AddRow($hListView, "8/15/2004|6|2|10/10/2010")
_AddRow($hListView, "10/05/2008|7||11/11/2011")
_AddRow($hListView, "11/05/2012|8|4|05/15/2005")
_AddRow($hListView, "12/05/2012|9|5|1/21/2004")
GUISetState()
_GUICtrlListView_RegisterSortCallBack($hListView)
EndFunc ;==>_Example1

Func sort()
Local $iCol = GUICtrlGetState($hListView)
Local $iRowCount = _GUICtrlListView_GetItemCount(ControlGetHandle("ListView Sort", "", $hListView))

; ----- If the column clicked contains date formated "MM/DD/YYYY" in the first, middle, or last
;    row, then convert to date format "YYYY/MM/DD" ----
If StringRegExp(_GUICtrlListView_GetItemText($hListView, 0, $iCol), "(d{1,2})[/.-](d{1,2})[/.-](d{4})") Or _
StringRegExp(_GUICtrlListView_GetItemText($hListView, $iRowCount - 1, $iCol), "(d{1,2})[/.-](d{1,2})[/.-](d{4})") Or _
StringRegExp(_GUICtrlListView_GetItemText($hListView, Int($iRowCount / 2), $iCol), "(d{1,2})[/.-](d{1,2})[/.-](d{4})") Then
Local $aItem2D[$iRowCount][2], $aTemp

For $i = 0 To $iRowCount - 1
$aItem2D[$i][0] = _GUICtrlListView_GetItemText($hListView, $i, $iCol)
If StringRegExp($aItem2D[$i][0], "(d{1,2})[/.-](d{1,2})[/.-](d{4})") Then
$aTemp = StringRegExp($aItem2D[$i][0], "(d+)", 3)
$aItem2D[$i][1] = StringFormat("%4d/%02d/%02d", $aTemp[2], $aTemp[0], $aTemp[1])
_GUICtrlListView_SetItem($hListView, $aItem2D[$i][1], $i, $iCol)
Else
$aItem2D[$i][1] = $aItem2D[$i][0]
_GUICtrlListView_SetItem($hListView, $aItem2D[$i][1], $i, $iCol)
EndIf
;ConsoleWrite($aItem2D[$i][0] & " " & $aItem2D[$i][1] & @LF)
Next
;ConsoleWrite(@LF)

; -------- Sort all columns ----------
_GUICtrlListView_SortItems($hListView, $iCol)

; -------- Convert date format "YYYY/MM/DD" back to the original format --------
For $i = 0 To $iRowCount - 1
For $j = 0 To $iRowCount - 1
If StringCompare(_GUICtrlListView_GetItemText($hListView, $i, $iCol), $aItem2D[$j][1]) = 0 Then
_GUICtrlListView_SetItem($hListView, $aItem2D[$j][0], $i, $iCol)
ExitLoop 1
EndIf
Next
Next
Else
_GUICtrlListView_SortItems($hListView, $iCol)
EndIf
EndFunc ;==>sort

Func _AddRow($hWnd, $sItem)
Local $aItem = StringSplit($sItem, "|"), $iColWidth
Local $iIndex = _GUICtrlListView_AddItem($hWnd, $aItem[1], -1, _GUICtrlListView_GetItemCount($hWnd))
_GUICtrlListView_SetColumnWidth($hWnd, 0, $LVSCW_AUTOSIZE_USEHEADER)
For $x = 2 To $aItem[0]
_GUICtrlListView_AddSubItem($hWnd, $iIndex, $aItem[$x], $x - 1)
_GUICtrlListView_SetColumnWidth($hWnd, $x - 1, $LVSCW_AUTOSIZE)
$iColWidth = _GUICtrlListView_GetColumnWidth($hWnd, $x - 1)
_GUICtrlListView_SetColumnWidth($hWnd, $x - 1, $LVSCW_AUTOSIZE_USEHEADER)
If $iColWidth > _GUICtrlListView_GetColumnWidth($hWnd, $x - 1) Then
_GUICtrlListView_SetColumnWidth($hWnd, $x - 1, $LVSCW_AUTOSIZE)
EndIf
Next
EndFunc ;==>_AddRow

Func CloseGUI()
_GUICtrlListView_UnRegisterSortCallBack($hListView)
GUIDelete()
Exit
EndFunc ;==>CloseGUI

Link to comment
Share on other sites

MilesAhead - That's seem to do a lot of overhead no?

I guess those guys who wrote the C/C++ standard libraries were fools. You're right! I wouldn't do anything the way they did. Too easy. Code everything new by hand. Not!! :)

Can't make 'em drink as the saying goes.

Edit: all seriousness aside.. the point is not that the general purpose routine always be used. Like most things it's a trade-off. Supposedly the existing part of the routine is already debugged if it's been in use for some time. It's efficient use of the developer's time since only the comparison function should have to be coded and debugged. But general purpose usually involves some overhead. One can't expect the run time and resource efficiency to compare with code customized to the particular requirements. It should be weighed if the savings in developer time is worth the overhead of slightly slower bulkier code. Often when I'm trying to make a small object in C++ and ask for advice on a particular facet of it, I'm told to use the STL. Well the reason I'm making my own object is I don't want the 337 methods already coded into the container that could be used when I'm only trying to buffer some data in memory, as example. There's no always right answer either way.

But unless you are sorting some really really big arrays on a really slow machine, I don't think you'll notice the extra "iCompare" param or the extra function call per comparison. But if you have a huge data set then by all means customize. The advantage of the code I grafted on is that it should be usable without breaking code already written that uses the _Array() UDF.

Edited by MilesAhead
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...