Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

CEGUIMultiColumnList.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002         filename:       CEGUIMultiColumnList.cpp
00003         created:        13/4/2004
00004         author:         Paul D Turner
00005         
00006         purpose:        Implementation of MultiColumnList widget base class
00007 *************************************************************************/
00008 /*************************************************************************
00009     Crazy Eddie's GUI System (http://www.cegui.org.uk)
00010     Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)
00011 
00012     This library is free software; you can redistribute it and/or
00013     modify it under the terms of the GNU Lesser General Public
00014     License as published by the Free Software Foundation; either
00015     version 2.1 of the License, or (at your option) any later version.
00016 
00017     This library is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020     Lesser General Public License for more details.
00021 
00022     You should have received a copy of the GNU Lesser General Public
00023     License along with this library; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 *************************************************************************/
00026 #include "elements/CEGUIMultiColumnList.h"
00027 #include "CEGUIExceptions.h"
00028 #include "elements/CEGUIScrollbar.h"
00029 #include "elements/CEGUIListHeader.h"
00030 #include "elements/CEGUIListboxItem.h"
00031 #include "CEGUILogger.h"
00032 #include "CEGUIPropertyHelper.h"
00033 #include <algorithm>
00034 
00035 
00036 // Start of CEGUI namespace section
00037 namespace CEGUI
00038 {
00039 const String MultiColumnList::EventNamespace("MultiColumnList");
00040 
00041 /*************************************************************************
00042         Properties for this class
00043 *************************************************************************/
00044 MultiColumnListProperties::ColumnsMovable                               MultiColumnList::d_columnsMovableProperty;
00045 MultiColumnListProperties::ColumnsSizable                               MultiColumnList::d_columnsSizableProperty;
00046 MultiColumnListProperties::ForceHorzScrollbar                   MultiColumnList::d_forceHorzScrollProperty;
00047 MultiColumnListProperties::ForceVertScrollbar                   MultiColumnList::d_forceVertScrollProperty;
00048 MultiColumnListProperties::NominatedSelectionColumnID   MultiColumnList::d_nominatedSelectColProperty;
00049 MultiColumnListProperties::NominatedSelectionRow                MultiColumnList::d_nominatedSelectRowProperty;
00050 MultiColumnListProperties::SelectionMode                                MultiColumnList::d_selectModeProperty;
00051 MultiColumnListProperties::SortColumnID                                 MultiColumnList::d_sortColumnIDProperty;
00052 MultiColumnListProperties::SortDirection                                MultiColumnList::d_sortDirectionProperty;
00053 MultiColumnListProperties::SortSettingEnabled                   MultiColumnList::d_sortSettingProperty;
00054 MultiColumnListProperties::ColumnHeader                                 MultiColumnList::d_columnHeaderProperty;
00055 MultiColumnListProperties::RowCount                                             MultiColumnList::d_rowCountProperty;
00056 
00057 /*************************************************************************
00058         Constants
00059 *************************************************************************/
00060 // Event names
00061 const String MultiColumnList::EventSelectionModeChanged( (utf8*)"SelectModeChanged" );
00062 const String MultiColumnList::EventNominatedSelectColumnChanged( (utf8*)"NomSelColChanged" );
00063 const String MultiColumnList::EventNominatedSelectRowChanged( (utf8*)"NomSelRowChanged" );
00064 const String MultiColumnList::EventVertScrollbarModeChanged( (utf8*)"VertBarModeChanged" );
00065 const String MultiColumnList::EventHorzScrollbarModeChanged( (utf8*)"HorzBarModeChanged" );
00066 const String MultiColumnList::EventSelectionChanged( (utf8*)"SelectionChanged" );
00067 const String MultiColumnList::EventListContentsChanged( (utf8*)"ContentsChanged" );
00068 const String MultiColumnList::EventSortColumnChanged( (utf8*)"SortColChanged" );
00069 const String MultiColumnList::EventSortDirectionChanged( (utf8*)"SortDirChanged" );
00070 const String MultiColumnList::EventListColumnSized( (utf8*)"ColSized" );
00071 const String MultiColumnList::EventListColumnMoved( (utf8*)"ColMoved" );
00072 
00073         
00074 /*************************************************************************
00075         Constructor for the Multi-column list base class
00076 *************************************************************************/
00077 MultiColumnList::MultiColumnList(const String& type, const String& name) :
00078         Window(type, name),
00079         d_forceVertScroll(false),
00080         d_forceHorzScroll(false),
00081         d_nominatedSelectCol(0),
00082         d_nominatedSelectRow(0),
00083         d_lastSelected(NULL)
00084 {
00085         // add multi-column list box specific events
00086         addMultiColumnListboxEvents();
00087 
00088         // add properties
00089         addMultiColumnListProperties();
00090 
00091         // set default selection mode
00092         d_selectMode = CellSingle;              // hack to ensure call below does what it should.
00093         setSelectionMode(RowSingle);
00094 }
00095 
00096 
00097 /*************************************************************************
00098         Destructor for the multi-column list base class.
00099 *************************************************************************/
00100 MultiColumnList::~MultiColumnList(void)
00101 {
00102         // delete any items we are supposed to
00103         resetList_impl();
00104 }
00105 
00106 
00107 /*************************************************************************
00108         Return whether user manipulation of the sort column and direction
00109         is enabled.
00110 *************************************************************************/
00111 bool MultiColumnList::isUserSortControlEnabled(void) const
00112 {
00113         return d_header->isSortingEnabled();
00114 }
00115 
00116 
00117 /*************************************************************************
00118         Return whether the user may size column segments.       
00119 *************************************************************************/
00120 bool MultiColumnList::isUserColumnSizingEnabled(void) const
00121 {
00122         return d_header->isColumnSizingEnabled();
00123 }
00124 
00125 
00126 /*************************************************************************
00127         Return whether the user may modify the order of the columns.    
00128 *************************************************************************/
00129 bool MultiColumnList::isUserColumnDraggingEnabled(void) const
00130 {
00131         return d_header->isColumnDraggingEnabled();
00132 }
00133 
00134 
00135 /*************************************************************************
00136         Return the number of columns in the multi-column list   
00137 *************************************************************************/
00138 uint MultiColumnList::getColumnCount(void) const
00139 {
00140         return d_header->getColumnCount();
00141 }
00142 
00143 
00144 /*************************************************************************
00145         Return the number of rows in the multi-column list.     
00146 *************************************************************************/
00147 uint MultiColumnList::getRowCount(void) const
00148 {
00149         return (uint)d_grid.size();
00150 }
00151 
00152 
00153 /*************************************************************************
00154         Return the zero based index of the current sort column.  There must
00155         be at least one column to successfully call this method.
00156 *************************************************************************/
00157 uint MultiColumnList::getSortColumn(void) const
00158 {
00159         return d_header->getSortColumn();
00160 }
00161 
00162 
00163 /*************************************************************************
00164         Return the zero based column index of the column with the specified ID.
00165 *************************************************************************/
00166 uint MultiColumnList::getColumnWithID(uint col_id) const
00167 {
00168         return d_header->getColumnFromID(col_id);
00169 }
00170 
00171 
00172 /*************************************************************************
00173         Return the zero based index of the column whos header text matches
00174         the specified text.     
00175 *************************************************************************/
00176 uint MultiColumnList::getColumnWithHeaderText(const String& text) const
00177 {
00178         return d_header->getColumnWithText(text);
00179 }
00180 
00181 
00182 /*************************************************************************
00183         Return the total width of all column headers.
00184 *************************************************************************/
00185 float MultiColumnList::getTotalColumnHeadersWidth(void) const
00186 {
00187         float width = d_header->getTotalSegmentsPixelExtent();
00188 
00189         if (getMetricsMode() == Relative)
00190         {
00191                 width = absoluteToRelativeX(width);
00192         }
00193 
00194         return width;
00195 }
00196 
00197 
00198 /*************************************************************************
00199         Return the width of the specified column header.        
00200 *************************************************************************/
00201 float MultiColumnList::getColumnHeaderWidth(uint col_idx) const
00202 {
00203         float width = d_header->getColumnPixelWidth(col_idx);
00204 
00205         if (getMetricsMode() == Relative)
00206         {
00207                 width = absoluteToRelativeX(width);
00208         }
00209 
00210         return width;
00211 }
00212 
00213 
00214 /*************************************************************************
00215         Return the currently set sort direction.
00216 *************************************************************************/
00217 ListHeaderSegment::SortDirection MultiColumnList::getSortDirection(void) const
00218 {
00219         return d_header->getSortDirection();
00220 }
00221 
00222 
00223 /*************************************************************************
00224         Return the ListHeaderSegment object for the specified column
00225 *************************************************************************/
00226 ListHeaderSegment& MultiColumnList::getHeaderSegmentForColumn(uint col_idx) const
00227 {
00228         return d_header->getSegmentFromColumn(col_idx);
00229 }
00230 
00231 
00232 /*************************************************************************
00233         return index of row containing the given ListboxItem
00234 *************************************************************************/
00235 uint MultiColumnList::getItemRowIndex(const ListboxItem* item) const
00236 {
00237         for (uint i = 0; i < getRowCount(); ++i)
00238         {
00239                 if (isListboxItemInRow(item, i))
00240                 {
00241                         return i;
00242                 }
00243 
00244         }
00245 
00246         // item is not attached to the list box, throw...
00247         throw InvalidRequestException((utf8*)"MultiColumnList::getItemRowIndex - the given ListboxItem is not attached to this MultiColumnList.");
00248 }
00249 
00250 
00251 /*************************************************************************
00252         return the index of the column containing the given ListboxItem
00253 *************************************************************************/
00254 uint MultiColumnList::getItemColumnIndex(const ListboxItem* item) const
00255 {
00256         for (uint i = 0; i < getColumnCount(); ++i)
00257         {
00258                 if (isListboxItemInColumn(item, i))
00259                 {
00260                         return i;
00261                 }
00262 
00263         }
00264 
00265         // item is not attached to the list box, throw...
00266         throw InvalidRequestException((utf8*)"MultiColumnList::getItemColumnIndex - the given ListboxItem is not attached to this MultiColumnList.");
00267 }
00268 
00269 
00270 /*************************************************************************
00271         return an MCLGridRef for the given ListboxItem.
00272 *************************************************************************/
00273 MCLGridRef MultiColumnList::getItemGridReference(const ListboxItem* item) const
00274 {
00275         return MCLGridRef(getItemRowIndex(item), getItemColumnIndex(item));
00276 }
00277 
00278 
00279 /*************************************************************************
00280         return a ListboxItem pointer for the given reference.
00281         May be NULL if position is blank.  Throws on out of range.
00282 *************************************************************************/
00283 ListboxItem* MultiColumnList::getItemAtGridReference(const MCLGridRef& grid_ref) const
00284 {
00285         // check for invalid grid ref
00286         if (grid_ref.column >= getColumnCount())
00287         {
00288                 throw InvalidRequestException((utf8*)"MultiColumnList::getItemAtGridReference - the column given in the grid reference is out of range.");
00289         }
00290         else if (grid_ref.row >= getRowCount())
00291         {
00292                 throw InvalidRequestException((utf8*)"MultiColumnList::getItemAtGridReference - the row given in the grid reference is out of range.");
00293         }
00294         else
00295         {
00296                 return d_grid[grid_ref.row][grid_ref.column];
00297         }
00298 
00299 }
00300 
00301 
00302 /*************************************************************************
00303         return true if the given item is in the given column.
00304 *************************************************************************/
00305 bool MultiColumnList::isListboxItemInColumn(const ListboxItem* item, uint col_idx) const
00306 {
00307         // check for invalid index
00308         if (col_idx >= getColumnCount())
00309         {
00310                 throw InvalidRequestException((utf8*)"MultiColumnList::isListboxItemInColumn - the column index given is out of range.");
00311         }
00312         else
00313         {
00314                 for (uint i = 0; i < getRowCount(); ++i)
00315                 {
00316                         if (d_grid[i][col_idx] == item)
00317                         {
00318                                 return true;
00319                         }
00320 
00321                 }
00322 
00323                 // Item was not in the column.
00324                 return false;
00325         }
00326 
00327 }
00328 
00329 
00330 /*************************************************************************
00331         return true if the given item is in the given row.
00332 *************************************************************************/
00333 bool MultiColumnList::isListboxItemInRow(const ListboxItem* item, uint row_idx) const
00334 {
00335         // check for invalid index
00336         if (row_idx >= getRowCount())
00337         {
00338                 throw InvalidRequestException((utf8*)"MultiColumnList::isListboxItemInRow - the row index given is out of range.");
00339         }
00340         else
00341         {
00342                 for (uint i = 0; i < getColumnCount(); ++i)
00343                 {
00344                         if (d_grid[row_idx][i] == item)
00345                         {
00346                                 return true;
00347                         }
00348 
00349                 }
00350 
00351                 // Item was not in the row.
00352                 return false;
00353         }
00354 
00355 }
00356 
00357 
00358 /*************************************************************************
00359         return true if the given item is somewhere in the list box.
00360 *************************************************************************/
00361 bool MultiColumnList::isListboxItemInList(const ListboxItem* item) const
00362 {
00363         for (uint i = 0; i < getRowCount(); ++i)
00364         {
00365                 for (uint j = 0; j < getColumnCount(); ++j)
00366                 {
00367                         if (d_grid[i][j] == item)
00368                         {
00369                                 return true;
00370                         }
00371 
00372                 }
00373 
00374         }
00375 
00376         return false;
00377 }
00378 
00379 
00380 /*************************************************************************
00381         Search the items in column 'col_idx' and return the first item after
00382         'start_item' that matches the specified text.  If 'start_item' is NULL
00383         searching start at (and includes) the first item in the column.
00384 *************************************************************************/
00385 ListboxItem* MultiColumnList::findColumnItemWithText(const String& text, uint col_idx, const ListboxItem* start_item) const
00386 {
00387         // ensure column is valid
00388         if (col_idx >= getColumnCount())
00389         {
00390                 throw InvalidRequestException((utf8*)"MultiColumnList::findColumnItemWithText - specified column index is out of range.");
00391         }
00392 
00393         // find start position for search
00394         uint i = (start_item == NULL) ? 0 : getItemRowIndex(start_item) + 1;
00395 
00396         for ( ; i < getRowCount(); ++i)
00397         {
00398                 // does this item match?
00399                 if (d_grid[i][col_idx]->getText() == text)
00400                 {
00401                         return d_grid[i][col_idx];
00402                 }
00403 
00404         }
00405 
00406         // no matching item.
00407         return NULL;
00408 }
00409 
00410 
00411 /*************************************************************************
00412         Search the items in row 'row_idx' and return the first item after
00413         'start_item' that matches the specified text.  If 'start_item' is NULL
00414         searching start at (and includes) the first item in the row.
00415 *************************************************************************/
00416 ListboxItem* MultiColumnList::findRowItemWithText(const String& text, uint row_idx, const ListboxItem* start_item) const
00417 {
00418         // ensure row is valid
00419         if (row_idx >= getRowCount())
00420         {
00421                 throw InvalidRequestException((utf8*)"MultiColumnList::findRowItemWithText - specified row index is out of range.");
00422         }
00423 
00424         // find start position for search
00425         uint i = (start_item == NULL) ? 0 : getItemColumnIndex(start_item) + 1;
00426 
00427         for ( ; i < getColumnCount(); ++i)
00428         {
00429                 // does this item match?
00430                 if (d_grid[row_idx][i]->getText() == text)
00431                 {
00432                         return d_grid[row_idx][i];
00433                 }
00434 
00435         }
00436 
00437         // no matching item.
00438         return NULL;
00439 }
00440 
00441 
00442 /*************************************************************************
00443         Search the list and return the first item after 'start_item' that
00444         matches the specified text.  If 'start_item' is NULL searching starts
00445         at (and includes) the first item in the list.
00446 
00447         Searching proceeds across the columns and down the rows.
00448 *************************************************************************/
00449 ListboxItem* MultiColumnList::findListItemWithText(const String& text, const ListboxItem* start_item) const
00450 {
00451         MCLGridRef startRef(0, 0);
00452         
00453         // get position of start_item if it's not NULL
00454         if (start_item != NULL)
00455         {
00456                 startRef = getItemGridReference(start_item);
00457                 ++startRef.column;
00458         }
00459 
00460         // perform the search
00461         for (uint i = startRef.row; i < getRowCount(); ++i)
00462         {
00463                 for (uint j = startRef.column; j < getColumnCount(); ++j)
00464                 {
00465                         // does this item match?
00466                         if (d_grid[i][j]->getText() == text)
00467                         {
00468                                 return d_grid[i][j];
00469                         }
00470 
00471                 }
00472 
00473         }
00474 
00475         // No match
00476         return NULL;
00477 }
00478 
00479 
00480 /*************************************************************************
00481         Scan the list (across columns for each row) and return the first
00482         selected item.
00483 *************************************************************************/
00484 ListboxItem* MultiColumnList::getFirstSelectedItem(void) const
00485 {
00486         return getNextSelected(NULL);
00487 }
00488 
00489 
00490 /*************************************************************************
00491         Search the list and return the first item after 'start_item' that
00492         is selected.  If 'start_item' is NULL searching starts at (and
00493         includes) the first item in the list.
00494 
00495         Searching proceeds across the columns and down the rows.
00496 *************************************************************************/
00497 ListboxItem* MultiColumnList::getNextSelected(const ListboxItem* start_item) const
00498 {
00499         MCLGridRef startRef(0, 0);
00500 
00501         // get position of start_item if it's not NULL
00502         if (start_item != NULL)
00503         {
00504                 startRef = getItemGridReference(start_item);
00505                 ++startRef.column;
00506         }
00507 
00508         // perform the search
00509         for (uint i = startRef.row; i < getRowCount(); ++i)
00510         {
00511                 for (uint j = startRef.column; j < getColumnCount(); ++j)
00512                 {
00513                         // does this item match?
00514                         ListboxItem* item = d_grid[i][j];
00515 
00516                         if ((item != NULL) && item->isSelected())
00517                         {
00518                                 return d_grid[i][j];
00519                         }
00520 
00521                 }
00522 
00523         }
00524 
00525         // No match
00526         return NULL;
00527 }
00528 
00529 
00530 /*************************************************************************
00531         Return the total number of selected items
00532 *************************************************************************/
00533 uint MultiColumnList::getSelectedCount(void) const
00534 {
00535         uint count = 0;
00536 
00537         for (uint i = 0; i < getRowCount(); ++i)
00538         {
00539                 for (uint j = 0; j < getColumnCount(); ++j)
00540                 {
00541                         ListboxItem* item = d_grid[i][j];
00542 
00543                         if ((item != NULL) && item->isSelected())
00544                         {
00545                                 ++count;
00546                         }
00547 
00548                 }
00549 
00550         }
00551 
00552         return count;
00553 }
00554 
00555 
00556 /*************************************************************************
00557         Return whether the item at the given grid position is selected.
00558 *************************************************************************/
00559 bool MultiColumnList::isItemSelected(const MCLGridRef& grid_ref) const
00560 {
00561         ListboxItem* item = getItemAtGridReference(grid_ref);
00562 
00563         if (item != NULL)
00564         {
00565                 return item->isSelected();
00566         }
00567 
00568         // if no item exists here, then it can't be selected.
00569         return false;
00570 }
00571 
00572 
00573 /*************************************************************************
00574         Return the ID of the nominated selection column
00575 *************************************************************************/
00576 uint MultiColumnList::getNominatedSelectionColumnID(void) const
00577 {
00578         return d_header->getSegmentFromColumn(d_nominatedSelectCol).getID();
00579 }
00580 
00581 
00582 /*************************************************************************
00583         Return the nominated selection column
00584 *************************************************************************/
00585 uint MultiColumnList::getNominatedSelectionColumn(void) const
00586 {
00587         return d_nominatedSelectCol;
00588 }
00589 
00590 
00591 /*************************************************************************
00592         Return the nominated selection row.
00593 *************************************************************************/
00594 uint MultiColumnList::getNominatedSelectionRow(void) const
00595 {
00596         return d_nominatedSelectRow;
00597 }
00598 
00599 
00600 /*************************************************************************
00601         Return the active selection mode.
00602 *************************************************************************/
00603 MultiColumnList::SelectionMode MultiColumnList::getSelectionMode(void) const
00604 {
00605         return d_selectMode;
00606 }
00607 
00608 
00609 /*************************************************************************
00610         Initialise the Window based object ready for use.
00611 *************************************************************************/
00612 void MultiColumnList::initialise(void)
00613 {
00614         // create the component sub-widgets
00615         d_vertScrollbar = createVertScrollbar(getName() + "__auto_vscrollbar__");
00616         d_horzScrollbar = createHorzScrollbar(getName() + "__auto_hscrollbar__");
00617         d_header                = createListHeader(getName() + "__auto_listheader__");
00618 
00619         // add components
00620         addChildWindow(d_vertScrollbar);
00621         addChildWindow(d_horzScrollbar);
00622         addChildWindow(d_header);
00623 
00624         // subscribe some events
00625         d_header->subscribeEvent(ListHeader::EventSegmentRenderOffsetChanged, Event::Subscriber(&CEGUI::MultiColumnList::handleHeaderScroll, this));
00626         d_header->subscribeEvent(ListHeader::EventSegmentSequenceChanged, Event::Subscriber(&CEGUI::MultiColumnList::handleHeaderSegMove, this));
00627         d_header->subscribeEvent(ListHeader::EventSegmentSized, Event::Subscriber(&CEGUI::MultiColumnList::handleColumnSizeChange, this));
00628         d_header->subscribeEvent(ListHeader::EventSortColumnChanged , Event::Subscriber(&CEGUI::MultiColumnList::handleSortColumnChange, this));
00629         d_header->subscribeEvent(ListHeader::EventSortDirectionChanged, Event::Subscriber(&CEGUI::MultiColumnList::handleSortDirectionChange, this));
00630         d_header->subscribeEvent(ListHeader::EventSplitterDoubleClicked, Event::Subscriber(&CEGUI::MultiColumnList::handleHeaderSegDblClick, this));
00631         d_horzScrollbar->subscribeEvent(Scrollbar::EventScrollPositionChanged, Event::Subscriber(&CEGUI::MultiColumnList::handleHorzScrollbar, this));
00632     d_vertScrollbar->subscribeEvent(Scrollbar::EventScrollPositionChanged, Event::Subscriber(&CEGUI::MultiColumnList::handleVertScrollbar, this));
00633 
00634 
00635         // final initialisation now widget is complete
00636         setSortDirection(ListHeaderSegment::None);
00637 
00638         // Perform initial layout
00639         configureScrollbars();
00640         performChildWindowLayout();
00641 }
00642 
00643 
00644 /*************************************************************************
00645         Remove all items from the list.
00646 *************************************************************************/
00647 void MultiColumnList::resetList(void)
00648 {
00649         if (resetList_impl())
00650         {
00651                 WindowEventArgs args(this);
00652                 onListContentsChanged(args);
00653         }
00654 
00655 }
00656 
00657 
00658 /*************************************************************************
00659         Add a column to the table.
00660 *************************************************************************/
00661 void MultiColumnList::addColumn(const String& text, uint col_id, float width)
00662 {
00663         insertColumn(text, col_id, width, getColumnCount());
00664 }
00665 
00666 
00667 /*************************************************************************
00668         Insert a column into the table.
00669 *************************************************************************/
00670 void MultiColumnList::insertColumn(const String& text, uint col_id, float width, uint position)
00671 {
00672         // if position is out of range, add item to end of current columns.
00673         if (position > getColumnCount())
00674         {
00675                 position = getColumnCount();
00676         }
00677 
00678         // get width as pixels
00679         if (getMetricsMode() == Relative)
00680         {
00681                 width = relativeToAbsoluteX(width);
00682         }
00683 
00684         // set-up the header for the new column.
00685         d_header->insertColumn(text, col_id, d_header->absoluteToRelativeX(width), position);
00686 
00687         // Insert a blank entry at the appropriate position in each row.
00688         for (uint i = 0; i < getRowCount(); ++i)
00689         {
00690                 d_grid[i].d_items.insert(d_grid[i].d_items.begin() + position, NULL);
00691         }
00692 
00693         // update stored nominated selection column if that has changed.
00694         if ((d_nominatedSelectCol >= position) && (getColumnCount() > 1))
00695         {
00696                 d_nominatedSelectCol++;
00697         }
00698 
00699         // signal a change to the list contents
00700         WindowEventArgs args(this);
00701         onListContentsChanged(args);
00702 }
00703 
00704 
00705 /*************************************************************************
00706         Remove a column from the table.
00707 *************************************************************************/
00708 void MultiColumnList::removeColumn(uint col_idx)
00709 {
00710         // ensure index is valid, and throw if not.
00711         if (col_idx >= getColumnCount())
00712         {
00713                 throw InvalidRequestException((utf8*)"MultiColumnList::removeColumn - the specified column index is out of range.");
00714         }
00715         else
00716         {
00717                 // update stored column index values
00718                 if (d_nominatedSelectCol == col_idx)
00719                 {
00720                         d_nominatedSelectCol = 0;
00721                 }
00722 
00723                 // remove the column from each row
00724                 for (uint i = 0; i < getRowCount(); ++i)
00725                 {
00726                         // extract the item pointer.
00727                         ListboxItem* item = d_grid[i][col_idx];
00728 
00729                         // remove the column entry from the row
00730                         d_grid[i].d_items.erase(d_grid[i].d_items.begin() + col_idx);
00731 
00732                         // delete the ListboxItem as needed.
00733                         if ((item != NULL) && item->isAutoDeleted())
00734                         {
00735                                 delete item;
00736                         }
00737 
00738                 }
00739 
00740                 // remove header segment
00741                 d_header->removeColumn(col_idx);
00742 
00743                 // signal a change to the list contents
00744                 WindowEventArgs args(this);
00745                 onListContentsChanged(args);
00746         }
00747 
00748 }
00749 
00750 
00751 /*************************************************************************
00752         Remove a column from the table (via ID)
00753 *************************************************************************/
00754 void MultiColumnList::removeColumnWithID(uint col_id)
00755 {
00756         removeColumn(getColumnWithID(col_id));
00757 }
00758 
00759 
00760 /*************************************************************************
00761         Move a column within the table
00762 *************************************************************************/
00763 void MultiColumnList::moveColumn(uint col_idx, uint position)
00764 {
00765         // move the segment on the header, events will ensure the items get moved also.
00766         d_header->moveColumn(col_idx, position);
00767 }
00768 
00769 
00770 /*************************************************************************
00771         Move a column (with specified ID) within the table.
00772 *************************************************************************/
00773 void MultiColumnList::moveColumnWithID(uint col_id, uint position)
00774 {
00775         moveColumn(getColumnWithID(col_id), position);
00776 }
00777 
00778 
00779 /*************************************************************************
00780         Add a row to the bottom of the table
00781 *************************************************************************/
00782 uint MultiColumnList::addRow(uint row_id)
00783 {
00784         return addRow(NULL, 0, row_id);
00785 }
00786 
00787 
00788 /*************************************************************************
00789         Add a row to the bottom of the table
00790 *************************************************************************/
00791 uint MultiColumnList::addRow(ListboxItem* item, uint col_id, uint row_id)
00792 {
00793         uint col_idx = 0;
00794 
00795         // Build the new row
00796         ListRow row;
00797         row.d_sortColumn = getSortColumn();
00798         row.d_items.resize(getColumnCount(), NULL);
00799         row.d_rowID = row_id;
00800 
00801         if (item != NULL)
00802         {
00803                 // discover which column to initially set
00804                 col_idx = getColumnWithID(col_id);
00805 
00806                 // establish item ownership & enter item into column
00807                 item->setOwnerWindow(this);
00808                 row[col_idx] = item;
00809         }
00810 
00811         uint pos;
00812 
00813         // if sorting is enabled, insert at an appropriate position
00814         if (getSortDirection() != ListHeaderSegment::None)
00815         {
00816         // calculate where the row should be inserted
00817         ListItemGrid::iterator ins_pos = std::upper_bound(d_grid.begin(), d_grid.end(), row);
00818         // insert item and get final inserted position.
00819         ListItemGrid::iterator final_pos = d_grid.insert(ins_pos, row);
00820                 // get final inserted position as an uint.
00821                 pos = (uint)std::distance(d_grid.begin(), final_pos);
00822         }
00823         // not sorted, just stick it on the end.
00824         else
00825         {
00826                 pos = getRowCount();
00827                 d_grid.push_back(row);
00828         }
00829 
00830         // signal a change to the list contents
00831         WindowEventArgs args(this);
00832         onListContentsChanged(args);
00833 
00834         return pos;
00835 }
00836 
00837 
00838 /*************************************************************************
00839         Insert a row into the table
00840 *************************************************************************/
00841 uint MultiColumnList::insertRow(uint row_idx, uint row_id)
00842 {
00843         return insertRow(NULL, 0, row_idx, row_id);
00844 }
00845 
00846 
00847 /*************************************************************************
00848         Insert a row into the table
00849 *************************************************************************/
00850 uint MultiColumnList::insertRow(ListboxItem* item, uint col_id, uint row_idx, uint row_id)
00851 {
00852         // if sorting is enabled, use add instead of insert
00853         if (getSortDirection() != ListHeaderSegment::None)
00854         {
00855                 return addRow(item, col_id);
00856         }
00857         else
00858         {
00859                 // Build the new row (empty)
00860                 ListRow row;
00861                 row.d_sortColumn = getSortColumn();
00862                 row.d_items.resize(getColumnCount(), NULL);
00863                 row.d_rowID = row_id;
00864 
00865                 // if row index is too big, just insert at end.
00866                 if (row_idx > getRowCount())
00867                 {
00868                         row_idx = getRowCount();
00869                 }
00870 
00871                 d_grid.insert(d_grid.begin() + row_idx, row);
00872 
00873                 // set the initial item in the new row
00874                 setItem(item, col_id, row_idx);
00875 
00876                 // signal a change to the list contents
00877                 WindowEventArgs args(this);
00878                 onListContentsChanged(args);
00879 
00880                 return row_idx;
00881         }
00882 
00883 }
00884 
00885 
00886 /*************************************************************************
00887         Remove a row from the list.
00888 *************************************************************************/
00889 void MultiColumnList::removeRow(uint row_idx)
00890 {
00891         // ensure row exists
00892         if (row_idx >= getRowCount())
00893         {
00894                 throw InvalidRequestException((utf8*)"MultiColumnList::removeRow - The specified row index is out of range.");
00895         }
00896         else
00897         {
00898                 // delete items we are supposed to
00899                 for (uint i = 0; i < getColumnCount(); ++i)
00900                 {
00901                         ListboxItem* item = d_grid[row_idx][i];
00902 
00903                         if ((item != NULL) && item->isAutoDeleted())
00904                         {
00905                                 delete item;
00906                         }
00907 
00908                 }
00909 
00910                 // erase the row from the grid.
00911                 d_grid.erase(d_grid.begin() + row_idx);
00912 
00913                 // if we have erased the selection row, reset that to 0
00914                 if (d_nominatedSelectRow == row_idx)
00915                 {
00916                         d_nominatedSelectRow = 0;
00917                 }
00918 
00919                 // signal a change to the list contents
00920                 WindowEventArgs args(this);
00921                 onListContentsChanged(args);
00922         }
00923 
00924 }
00925 
00926 
00927 /*************************************************************************
00928         Replace the item at grid-ref 'position' with 'item'.
00929         The old item is deleted according to the items auto-delete setting
00930 *************************************************************************/
00931 void MultiColumnList::setItem(ListboxItem* item, const MCLGridRef& position)
00932 {
00933         // validate grid ref
00934         if (position.column >= getColumnCount())
00935         {
00936                 throw InvalidRequestException((utf8*)"MultiColumnList::setItem - the specified column index is invalid.");
00937         }
00938         else if (position.row >= getRowCount())
00939         {
00940                 throw InvalidRequestException((utf8*)"MultiColumnList::setItem - the specified row index is invalid.");
00941         }
00942 
00943         // delete old item as required
00944         ListboxItem* oldItem = d_grid[position.row][position.column];
00945 
00946         if ((oldItem != NULL) && oldItem->isAutoDeleted())
00947         {
00948                 delete oldItem;
00949         }
00950 
00951         // set new item.
00952         if (item != NULL)
00953                 item->setOwnerWindow(this);
00954 
00955         d_grid[position.row][position.column] = item;
00956 
00957 
00958         // signal a change to the list contents
00959         WindowEventArgs args(this);
00960         onListContentsChanged(args);
00961 }
00962 
00963 
00964 /*************************************************************************
00965         Replace the item in row 'row_idx', in the column with ID 'col_id'
00966         with 'item'.  The old item is deleted as required.
00967 *************************************************************************/
00968 void MultiColumnList::setItem(ListboxItem* item, uint col_id, uint row_idx)
00969 {
00970         setItem(item, MCLGridRef(row_idx, getColumnWithID(col_id)));
00971 }
00972 
00973 
00974 /*************************************************************************
00975         Set the current selection mode.
00976 *************************************************************************/
00977 void MultiColumnList::setSelectionMode(MultiColumnList::SelectionMode sel_mode)
00978 {
00979         if (d_selectMode != sel_mode)
00980         {
00981                 d_selectMode = sel_mode;
00982 
00983                 clearAllSelections();
00984 
00985                 switch(d_selectMode)
00986                 {
00987                 case RowSingle:
00988                         d_multiSelect           = false;
00989                         d_fullRowSelect         = true;
00990                         d_fullColSelect         = false;
00991                         d_useNominatedCol       = false;
00992                         d_useNominatedRow       = false;
00993                         break;
00994 
00995                 case RowMultiple:
00996                         d_multiSelect           = true;
00997                         d_fullRowSelect         = true;
00998                         d_fullColSelect         = false;
00999                         d_useNominatedCol       = false;
01000                         d_useNominatedRow       = false;
01001                         break;
01002 
01003                 case CellSingle:
01004                         d_multiSelect           = false;
01005                         d_fullRowSelect         = false;
01006                         d_fullColSelect         = false;
01007                         d_useNominatedCol       = false;
01008                         d_useNominatedRow       = false;
01009                         break;
01010 
01011                 case CellMultiple:
01012                         d_multiSelect           = true;
01013                         d_fullRowSelect         = false;
01014                         d_fullColSelect         = false;
01015                         d_useNominatedCol       = false;
01016                         d_useNominatedRow       = false;
01017                         break;
01018 
01019                 case NominatedColumnSingle:
01020                         d_multiSelect           = false;
01021                         d_fullRowSelect         = false;
01022                         d_fullColSelect         = false;
01023                         d_useNominatedCol       = true;
01024                         d_useNominatedRow       = false;
01025                         break;
01026 
01027                 case NominatedColumnMultiple:
01028                         d_multiSelect           = true;
01029                         d_fullRowSelect         = false;
01030                         d_fullColSelect         = false;
01031                         d_useNominatedCol       = true;
01032                         d_useNominatedRow       = false;
01033                         break;
01034 
01035                 case ColumnSingle:
01036                         d_multiSelect           = false;
01037                         d_fullRowSelect         = false;
01038                         d_fullColSelect         = true;
01039                         d_useNominatedCol       = false;
01040                         d_useNominatedRow       = false;
01041                         break;
01042 
01043                 case ColumnMultiple:
01044                         d_multiSelect           = true;
01045                         d_fullRowSelect         = false;
01046                         d_fullColSelect         = true;
01047                         d_useNominatedCol       = false;
01048                         d_useNominatedRow       = false;
01049                         break;
01050 
01051                 case NominatedRowSingle:
01052                         d_multiSelect           = false;
01053                         d_fullRowSelect         = false;
01054                         d_fullColSelect         = false;
01055                         d_useNominatedCol       = false;
01056                         d_useNominatedRow       = true;
01057                         break;
01058 
01059                 case NominatedRowMultiple:
01060                         d_multiSelect           = true;
01061                         d_fullRowSelect         = false;
01062                         d_fullColSelect         = false;
01063                         d_useNominatedCol       = false;
01064                         d_useNominatedRow       = true;
01065                         break;
01066 
01067                 default:
01068                         throw InvalidRequestException((utf8*)"MultiColumnList::setSelectionMode - invalid or unknown SelectionMode value supplied.");
01069                         break;
01070 
01071                 }
01072 
01073                 // Fire event.
01074                 WindowEventArgs args(this);
01075                 onSelectionModeChanged(args);
01076         }
01077 
01078 }
01079 
01080 
01081 /*************************************************************************
01082         Set the nominated column for 'NominatedColumn*' selections (by ID)
01083 *************************************************************************/
01084 void MultiColumnList::setNominatedSelectionColumnID(uint col_id)
01085 {
01086         setNominatedSelectionColumn(getColumnWithID(col_id));
01087 }
01088 
01089 
01090 /*************************************************************************
01091         Set the nominated column for 'NominatedColumn*' selections (by Index)
01092 *************************************************************************/
01093 void MultiColumnList::setNominatedSelectionColumn(uint col_idx)
01094 {
01095         if (d_nominatedSelectCol != col_idx)
01096         {
01097                 clearAllSelections();
01098 
01099                 d_nominatedSelectCol = col_idx;
01100 
01101                 // Fire event.
01102                 WindowEventArgs args(this);
01103                 onNominatedSelectColumnChanged(args);
01104         }
01105 
01106 }
01107 
01108 
01109 /*************************************************************************
01110         Set the nominated row for 'NominatedRow*' selections
01111 *************************************************************************/
01112 void MultiColumnList::setNominatedSelectionRow(uint row_idx)
01113 {
01114         if (d_nominatedSelectRow != row_idx)
01115         {
01116                 clearAllSelections();
01117 
01118                 d_nominatedSelectRow = row_idx;
01119 
01120                 // Fire event.
01121                 WindowEventArgs args(this);
01122                 onNominatedSelectRowChanged(args);
01123         }
01124 
01125 }
01126 
01127 
01128 /*************************************************************************
01129         Set the current sort direction.
01130 *************************************************************************/
01131 void MultiColumnList::setSortDirection(ListHeaderSegment::SortDirection direction)
01132 {
01133         if (getSortDirection() != direction)
01134         {
01135                 // set the sort direction on the header, events will make sure everything else is updated.
01136                 d_header->setSortDirection(direction);
01137         }
01138 
01139 }
01140 
01141 
01142 /*************************************************************************
01143         Set the current sort column (by index)
01144 *************************************************************************/
01145 void MultiColumnList::setSortColumn(uint col_idx)
01146 {
01147         if (getSortColumn() != col_idx)
01148         {
01149                 // set the sort column on the header, events will make sure everything else is updated.
01150                 d_header->setSortColumn(col_idx);
01151         }
01152 
01153 }
01154 
01155 
01156 /*************************************************************************
01157         Set the current sort column (by ID)
01158 *************************************************************************/
01159 void MultiColumnList::setSortColumnByID(uint col_id)
01160 {
01161         if (d_header->getSegmentFromColumn(getSortColumn()).getID() != col_id)
01162         {
01163                 // set the sort column on the header, events will make sure everything else is updated.
01164                 d_header->setSortColumnFromID(col_id);
01165         }
01166 
01167 }
01168 
01169 
01170 /*************************************************************************
01171         Enable / Disable forced display of the vertical scroll bar
01172 *************************************************************************/
01173 void MultiColumnList::setShowVertScrollbar(bool setting)
01174 {
01175         if (d_forceVertScroll != setting)
01176         {
01177                 d_forceVertScroll = setting;
01178 
01179                 configureScrollbars();
01180 
01181                 // Event firing.
01182                 WindowEventArgs args(this);
01183                 onVertScrollbarModeChanged(args);
01184         }
01185 
01186 }
01187 
01188 
01189 /*************************************************************************
01190         Enable / Disable forced display of the horizontal scroll bar
01191 *************************************************************************/
01192 void MultiColumnList::setShowHorzScrollbar(bool setting)
01193 {
01194         if (d_forceHorzScroll != setting)
01195         {
01196                 d_forceHorzScroll = setting;
01197 
01198                 configureScrollbars();
01199 
01200                 // Event firing.
01201                 WindowEventArgs args(this);
01202                 onHorzScrollbarModeChanged(args);
01203         }
01204 
01205 }
01206 
01207 
01208 /*************************************************************************
01209         Clear the selected state from all currently selected items.
01210 *************************************************************************/
01211 void MultiColumnList::clearAllSelections(void)
01212 {
01213         // only fire events and update if we actually made any changes
01214         if (clearAllSelections_impl())
01215         {
01216                 // Fire event.
01217                 WindowEventArgs args(this);
01218                 onSelectionChanged(args);
01219         }
01220 
01221 
01222 }
01223 
01224 
01225 /*************************************************************************
01226         Set the selected state of 'item' (must be attached to the list box)
01227 *************************************************************************/
01228 void MultiColumnList::setItemSelectState(ListboxItem* item, bool state)
01229 {
01230         setItemSelectState(getItemGridReference(item), state);
01231 }
01232 
01233 
01234 /*************************************************************************
01235         Set the selected state of the item at 'grid_ref'.
01236 *************************************************************************/
01237 void MultiColumnList::setItemSelectState(const MCLGridRef& grid_ref, bool state)
01238 {
01239         if (setItemSelectState_impl(grid_ref, state))
01240         {
01241                 // Fire event.
01242                 WindowEventArgs args(this);
01243                 onSelectionChanged(args);
01244         }
01245 
01246 }
01247 
01248 
01249 /*************************************************************************
01250         Update the list box internal state after attached items have been
01251         externally modified.
01252 *************************************************************************/
01253 void MultiColumnList::handleUpdatedItemData(void)
01254 {
01255         configureScrollbars();
01256         requestRedraw();
01257 }
01258 
01259 
01260 /*************************************************************************
01261         Set the width of the specified column header (and therefore the
01262         column itself). 
01263 *************************************************************************/
01264 void MultiColumnList::setColumnHeaderWidth(uint col_idx, float width)
01265 {
01266         if (getMetricsMode() == Relative)
01267         {
01268                 width = relativeToAbsoluteX(width);
01269         }
01270 
01271         d_header->setColumnPixelWidth(col_idx, width);
01272 }
01273 
01274 
01275 /*************************************************************************
01276         Add multi column list box specific events       
01277 *************************************************************************/
01278 void MultiColumnList::addMultiColumnListboxEvents(void)
01279 {
01280         addEvent(EventSelectionModeChanged);                    addEvent(EventNominatedSelectColumnChanged);
01281         addEvent(EventNominatedSelectRowChanged);               addEvent(EventVertScrollbarModeChanged);
01282         addEvent(EventHorzScrollbarModeChanged);                addEvent(EventSelectionChanged);
01283         addEvent(EventListContentsChanged);                             addEvent(EventSortColumnChanged);
01284         addEvent(EventSortDirectionChanged);                    addEvent(EventListColumnMoved);
01285         addEvent(EventListColumnSized);
01286 }
01287 
01288 
01289 /*************************************************************************
01290         display required integrated scroll bars according to current state
01291         of the list box and update their values.        
01292 *************************************************************************/
01293 void MultiColumnList::configureScrollbars(void)
01294 {
01295         float totalHeight       = getTotalRowsHeight();
01296         float fullWidth         = d_header->getTotalSegmentsPixelExtent();
01297 
01298         //
01299         // First show or hide the scroll bars as needed (or requested)
01300         //
01301         // show or hide vertical scroll bar as required (or as specified by option)
01302         if ((totalHeight > getListRenderArea().getHeight()) || d_forceVertScroll)
01303         {
01304                 d_vertScrollbar->show();
01305 
01306                 // show or hide horizontal scroll bar as required (or as specified by option)
01307                 if ((fullWidth > getListRenderArea().getWidth()) || d_forceHorzScroll)
01308                 {
01309                         d_horzScrollbar->show();
01310                 }
01311                 else
01312                 {
01313                         d_horzScrollbar->hide();
01314                 }
01315 
01316         }
01317         else
01318         {
01319                 // show or hide horizontal scroll bar as required (or as specified by option)
01320                 if ((fullWidth > getListRenderArea().getWidth()) || d_forceHorzScroll)
01321                 {
01322                         d_horzScrollbar->show();
01323 
01324                         // show or hide vertical scroll bar as required (or as specified by option)
01325                         if ((totalHeight > getListRenderArea().getHeight()) || d_forceVertScroll)
01326                         {
01327                                 d_vertScrollbar->show();
01328                         }
01329                         else
01330                         {
01331                                 d_vertScrollbar->hide();
01332                         }
01333 
01334                 }
01335                 else
01336                 {
01337                         d_vertScrollbar->hide();
01338                         d_horzScrollbar->hide();
01339                 }
01340 
01341         }
01342 
01343         //
01344         // Set up scroll bar values
01345         //
01346         Rect renderArea(getListRenderArea());
01347 
01348         d_vertScrollbar->setDocumentSize(totalHeight);
01349         d_vertScrollbar->setPageSize(renderArea.getHeight());
01350         d_vertScrollbar->setStepSize(ceguimax(1.0f, renderArea.getHeight() / 10.0f));
01351         d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition());
01352 
01353         d_horzScrollbar->setDocumentSize(fullWidth);
01354         d_horzScrollbar->setPageSize(renderArea.getWidth());
01355         d_horzScrollbar->setStepSize(ceguimax(1.0f, renderArea.getWidth() / 10.0f));
01356         d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition());
01357 }
01358 
01359 
01360 /*************************************************************************
01361         select all strings between positions 'start' and 'end'.  (inclusive)    
01362 *************************************************************************/
01363 bool MultiColumnList::selectRange(const MCLGridRef& start, const MCLGridRef& end)
01364 {
01365         MCLGridRef tmpStart(start);
01366         MCLGridRef tmpEnd(end);
01367 
01368         // ensure start is before end
01369         if (tmpStart.column > tmpEnd.column)
01370         {
01371                 tmpStart.column = tmpEnd.column;
01372                 tmpEnd.column = start.column;
01373         }
01374 
01375         if (tmpStart.row > tmpEnd.row)
01376         {
01377                 tmpStart.row = tmpEnd.row;
01378                 tmpEnd.row = start.row;
01379         }
01380 
01381         bool modified = false;
01382 
01383         // loop through all items selecting them.
01384         for (uint i = tmpStart.row; i <= tmpEnd.row; ++i)
01385         {
01386                 for (uint j = tmpStart.column; j <= tmpEnd.column; ++j)
01387                 {
01388                         ListboxItem* item = d_grid[i][j];
01389 
01390                         if (item != NULL)
01391                         {
01392                                 modified |= setItemSelectState_impl(getItemGridReference(item), true);
01393                         }
01394 
01395                 }
01396 
01397         }
01398 
01399         return modified;
01400 }
01401 
01402 
01403 /*************************************************************************
01404         Return the sum of all row heights       
01405 *************************************************************************/
01406 float MultiColumnList::getTotalRowsHeight(void) const
01407 {
01408         float height = 0.0f;
01409 
01410         for (uint i = 0; i < getRowCount(); ++i)
01411         {
01412                 height += getHighestRowItemHeight(i);
01413         }
01414 
01415         return height;
01416 }
01417 
01418 
01419 /*************************************************************************
01420         Return the width of the widest item in the given column 
01421 *************************************************************************/
01422 float MultiColumnList::getWidestColumnItemWidth(uint col_idx) const
01423 {
01424         if (col_idx >= getColumnCount())
01425         {
01426                 throw InvalidRequestException((utf8*)"MultiColumnList::getWidestColumnItemWidth - specified column is out of range.");
01427         }
01428         else
01429         {
01430                 float width = 0.0f;
01431 
01432                 // check each item in the column
01433                 for (uint i = 0; i < getRowCount(); ++i)
01434                 {
01435                         ListboxItem* item = d_grid[i][col_idx];
01436 
01437                         // if the slot has an item in it
01438                         if (item != NULL)
01439                         {
01440                                 Size sz(item->getPixelSize());
01441 
01442                                 // see if this item is wider than the previous widest
01443                                 if (sz.d_width > width)
01444                                 {
01445                                         // update current widest
01446                                         width = sz.d_width;
01447                                 }
01448 
01449                         }
01450 
01451                 }
01452 
01453                 // return the widest item.
01454                 return width;
01455         }
01456 
01457 }
01458 
01459 
01460 /*************************************************************************
01461         Return the height of the highest item in the given row. 
01462 *************************************************************************/
01463 float MultiColumnList::getHighestRowItemHeight(uint row_idx) const
01464 {
01465         if (row_idx >= getRowCount())
01466         {
01467                 throw InvalidRequestException((utf8*)"MultiColumnList::getHighestRowItemHeight - specified row is out of range.");
01468         }
01469         else
01470         {
01471                 float height = 0.0f;
01472 
01473                 // check each item in the column
01474                 for (uint i = 0; i < getColumnCount(); ++i)
01475                 {
01476                         ListboxItem* item = d_grid[row_idx][i];
01477 
01478                         // if the slot has an item in it
01479                         if (item != NULL)
01480                         {
01481                                 Size sz(item->getPixelSize());
01482 
01483                                 // see if this item is higher than the previous highest
01484                                 if (sz.d_height > height)
01485                                 {
01486                                         // update current highest
01487                                         height = sz.d_height;
01488                                 }
01489 
01490                         }
01491 
01492                 }
01493 
01494                 // return the hightest item.
01495                 return height;
01496         }
01497         
01498 }
01499 
01500 
01501 /*************************************************************************
01502         Clear the selected state for all items (implementation) 
01503 *************************************************************************/
01504 bool MultiColumnList::clearAllSelections_impl(void)
01505 {
01506         // flag used so we can track if we did anything.
01507         bool modified = false;
01508 
01509         for (uint i = 0; i < getRowCount(); ++i)
01510         {
01511                 for (uint j = 0; j < getColumnCount(); ++j)
01512                 {
01513                         ListboxItem* item = d_grid[i][j];
01514 
01515                         // if slot has an item, and item is selected
01516                         if ((item != NULL) && item->isSelected())
01517                         {
01518                                 // clear selection state and set modified flag
01519                                 item->setSelected(false);
01520                                 modified = true;
01521                         }
01522 
01523                 }
01524 
01525         }
01526 
01527         // signal whether or not we did anything.
01528         return modified;
01529 }
01530 
01531 
01532 /*************************************************************************
01533         Return the ListboxItem under the given window local pixel co-ordinate.  
01534 *************************************************************************/
01535 ListboxItem* MultiColumnList::getItemAtPoint(const Point& pt) const
01536 {
01537         Rect listArea(getListRenderArea());
01538 
01539         float y = listArea.d_top - d_vertScrollbar->getScrollPosition();
01540         float x = listArea.d_left - d_horzScrollbar->getScrollPosition();
01541 
01542         for (uint i = 0; i < getRowCount(); ++i)
01543         {
01544                 y += getHighestRowItemHeight(i);
01545 
01546                 // have we located the row?
01547                 if (pt.d_y < y)
01548                 {
01549                         // scan across to find column that was clicked
01550                         for (uint j = 0; j < getColumnCount(); ++j)
01551                         {
01552                                 x += d_header->getColumnPixelWidth(j);
01553 
01554                                 // was this the column?
01555                                 if (pt.d_x < x)
01556                                 {
01557                                         // return contents of grid element that was clicked.
01558                                         return d_grid[i][j];
01559                                 }
01560 
01561                         }
01562 
01563                 }
01564 
01565         }
01566 
01567         return NULL;
01568 }
01569 
01570 
01571 /*************************************************************************
01572         Set select state for the given item.  This appropriately selects other
01573         items depending upon the select mode.  Returns true if something is
01574         changed, else false.    
01575 *************************************************************************/
01576 bool MultiColumnList::setItemSelectState_impl(const MCLGridRef grid_ref, bool state)
01577 {
01578         // validate grid ref
01579         if (grid_ref.column >= getColumnCount())
01580         {
01581                 throw InvalidRequestException((utf8*)"MultiColumnList::setItemSelectState - the specified column index is invalid.");
01582         }
01583         else if (grid_ref.row >= getRowCount())
01584         {
01585                 throw InvalidRequestException((utf8*)"MultiColumnList::setItemSelectState - the specified row index is invalid.");
01586         }
01587 
01588         // only do this if the setting is changing
01589         if (d_grid[grid_ref.row][grid_ref.column]->isSelected() != state)
01590         {
01591                 // if using nominated selection row and/ or column, check that they match.
01592                 if ((!d_useNominatedCol || (d_nominatedSelectCol == grid_ref.column)) &&
01593                         (!d_useNominatedRow || (d_nominatedSelectRow == grid_ref.row)))
01594                 {
01595                         // clear current selection if not multi-select box
01596                         if (state && (!d_multiSelect))
01597                         {
01598                                 clearAllSelections_impl();
01599                         }
01600 
01601                         // full row?
01602                         if (d_fullRowSelect)
01603                         {
01604                                 // clear selection on all items in the row
01605                                 setSelectForItemsInRow(grid_ref.row, state);
01606                         }
01607                         // full column?
01608                         else if (d_fullColSelect)
01609                         {
01610                                 // clear selection on all items in the column
01611                                 setSelectForItemsInColumn(grid_ref.column, state);
01612 
01613                         }
01614                         // single item to be affected
01615                         else
01616                         {
01617                                 d_grid[grid_ref.row][grid_ref.column]->setSelected(state);
01618                         }
01619 
01620                         return true;
01621                 }
01622 
01623         }
01624 
01625         return false;
01626 }
01627 
01628 
01629 /*************************************************************************
01630         Select all items in the given row       
01631 *************************************************************************/
01632 void MultiColumnList::setSelectForItemsInRow(uint row_idx, bool state)
01633 {
01634         for (uint i = 0; i < getColumnCount(); ++i)
01635         {
01636                 ListboxItem* item = d_grid[row_idx][i];
01637 
01638                 if (item != NULL)
01639                 {
01640                         item->setSelected(state);
01641                 }
01642 
01643         }
01644 
01645 }
01646 
01647 
01648 /*************************************************************************
01649         Select all items in the given column
01650 *************************************************************************/
01651 void MultiColumnList::setSelectForItemsInColumn(uint col_idx, bool state)
01652 {
01653         for (uint i = 0; i < getRowCount(); ++i)
01654         {
01655                 ListboxItem* item = d_grid[i][col_idx];
01656 
01657                 if (item != NULL)
01658                 {
01659                         item->setSelected(state);
01660                 }
01661 
01662         }
01663 
01664 }
01665 
01666 /*************************************************************************
01667         Move the column at index 'col_idx' so it is at index 'position'.
01668         
01669         Implementation version which does not move the header segment
01670         (since that may have already happned).
01671 *************************************************************************/
01672 void MultiColumnList::moveColumn_impl(uint col_idx, uint position)
01673 {
01674         // ensure index is valid, and throw if not.
01675         if (col_idx >= getColumnCount())
01676         {
01677                 throw InvalidRequestException((utf8*)"MultiColumnList::moveColumn - the specified source column index is out of range.");
01678         }
01679         else
01680         {
01681                 // if position is too big, insert at end.
01682                 if (position > getColumnCount())
01683                 {
01684                         position = getColumnCount();
01685                 }
01686 
01687                 // update select column index value if needed
01688                 if (d_nominatedSelectCol == col_idx)
01689                 {
01690                         d_nominatedSelectCol = position;
01691                 }
01692                 else if ((col_idx < d_nominatedSelectCol) && (position >= d_nominatedSelectCol))
01693                 {
01694                         d_nominatedSelectCol--;
01695                 }
01696                 else if ((col_idx > d_nominatedSelectCol) && (position <= d_nominatedSelectCol))
01697                 {
01698                         d_nominatedSelectCol++;
01699                 }
01700 
01701                 // move column entry in each row.
01702                 for (uint i = 0; i < getRowCount(); ++i)
01703                 {
01704                         // store entry.
01705                         ListboxItem* item = d_grid[i][col_idx];
01706 
01707                         // remove the original column for this row.
01708                         d_grid[i].d_items.erase(d_grid[i].d_items.begin() + col_idx);
01709 
01710                         // insert entry at its new position
01711                         d_grid[i].d_items.insert(d_grid[i].d_items.begin() + position, item);
01712                 }
01713 
01714         }
01715 
01716 }
01717 
01718 
01719 
01720 /*************************************************************************
01721         renders the widget
01722 *************************************************************************/
01723 void MultiColumnList::populateRenderCache()
01724 {
01725     // get the derived class to render general stuff before we handle the items
01726     cacheListboxBaseImagery();
01727 
01728     //
01729     // Render list items
01730     //
01731     Vector3     itemPos;
01732     Size        itemSize;
01733     Rect        itemClipper, itemRect;;
01734 
01735     // calculate position of area we have to render into
01736     Rect itemsArea(getListRenderArea());
01737     
01738     //absarea.offset(getUnclippedPixelRect().getPosition());
01739 
01740 //      // calculate clipper for list rendering area
01741 //      Rect clipper(absarea.getIntersection(getPixelRect()));
01742 
01743     // set up initial positional details for items
01744     itemPos.d_y = itemsArea.d_top - d_vertScrollbar->getScrollPosition();
01745     itemPos.d_z = System::getSingleton().getRenderer()->getZLayer(3) - System::getSingleton().getRenderer()->getCurrentZ();
01746 
01747     float alpha = getEffectiveAlpha();
01748 
01749     // loop through the items
01750     for (uint i = 0; i < getRowCount(); ++i)
01751     {
01752         // set initial x position for this row.
01753         itemPos.d_x = itemsArea.d_left - d_horzScrollbar->getScrollPosition();
01754 
01755         // calculate height for this row.
01756         itemSize.d_height = getHighestRowItemHeight(i);
01757 
01758         // loop through the columns in this row
01759         for (uint j = 0; j < getColumnCount(); ++j)
01760         {
01761             // allow item to use full width of the column
01762             itemSize.d_width = d_header->getColumnPixelWidth(j);
01763 
01764             ListboxItem* item = d_grid[i][j];
01765 
01766             // is the item for this column set?
01767             if (item)
01768             {
01769                 // calculate destination area for this item.
01770                 itemRect.d_left = itemPos.d_x;
01771                 itemRect.d_top  = itemPos.d_y;
01772                 itemRect.setSize(itemSize);
01773                 itemClipper = itemRect.getIntersection(itemsArea);
01774 
01775                 // skip this item if totally clipped
01776                 if (itemClipper.getWidth() == 0)
01777                 {
01778                     itemPos.d_x += itemSize.d_width;
01779                     continue;
01780                 }
01781 
01782                 // draw this item
01783                 item->draw(d_renderCache, itemRect, itemPos.d_z, alpha, &itemClipper);
01784             }
01785 
01786             // update position for next column.
01787             itemPos.d_x += itemSize.d_width;
01788         }
01789 
01790         // update position ready for next row
01791         itemPos.d_y += itemSize.d_height;
01792     }
01793 
01794 }
01795 
01796 
01797 /*************************************************************************
01798         Handler called when selection mode changes
01799 *************************************************************************/
01800 void MultiColumnList::onSelectionModeChanged(WindowEventArgs& e)
01801 {
01802         fireEvent(EventSelectionModeChanged, e, EventNamespace);
01803 }
01804 
01805 
01806 /*************************************************************************
01807         Handler called when the nominated selection column changes
01808 *************************************************************************/
01809 void MultiColumnList::onNominatedSelectColumnChanged(WindowEventArgs& e)
01810 {
01811         fireEvent(EventNominatedSelectColumnChanged, e, EventNamespace);
01812 }
01813 
01814 
01815 /*************************************************************************
01816         Handler called when nominated selection row changes
01817 *************************************************************************/
01818 void MultiColumnList::onNominatedSelectRowChanged(WindowEventArgs& e)
01819 {
01820         fireEvent(EventNominatedSelectRowChanged, e, EventNamespace);
01821 }
01822 
01823 
01824 /*************************************************************************
01825         Handler called when vertcial scroll bar 'force' mode changes
01826 *************************************************************************/
01827 void MultiColumnList::onVertScrollbarModeChanged(WindowEventArgs& e)
01828 {
01829         fireEvent(EventVertScrollbarModeChanged, e, EventNamespace);
01830 }
01831 
01832 
01833 /*************************************************************************
01834         Handler called when horizontal scroll bar 'force' mode changes
01835 *************************************************************************/
01836 void MultiColumnList::onHorzScrollbarModeChanged(WindowEventArgs& e)
01837 {
01838         fireEvent(EventHorzScrollbarModeChanged, e, EventNamespace);
01839 }
01840 
01841 
01842 /*************************************************************************
01843         Handler called when the current selection in the list changes.
01844 *************************************************************************/
01845 void MultiColumnList::onSelectionChanged(WindowEventArgs& e)
01846 {
01847         requestRedraw();
01848         fireEvent(EventSelectionChanged, e, EventNamespace);
01849 }
01850 
01851 
01852 /*************************************************************************
01853         Handler called when list contents changes
01854 *************************************************************************/
01855 void MultiColumnList::onListContentsChanged(WindowEventArgs& e)
01856 {
01857         configureScrollbars();
01858         requestRedraw();
01859         fireEvent(EventListContentsChanged, e, EventNamespace);
01860 }
01861 
01862 
01863 /*************************************************************************
01864         Handler called when the sort column changes
01865 *************************************************************************/
01866 void MultiColumnList::onSortColumnChanged(WindowEventArgs& e)
01867 {
01868         requestRedraw();
01869         fireEvent(EventSortColumnChanged, e, EventNamespace);
01870 }
01871 
01872 
01873 /*************************************************************************
01874         Handler called when the sort direction changes
01875 *************************************************************************/
01876 void MultiColumnList::onSortDirectionChanged(WindowEventArgs& e)
01877 {
01878         requestRedraw();
01879         fireEvent(EventSortDirectionChanged, e, EventNamespace);
01880 }
01881 
01882 
01883 /*************************************************************************
01884         Handler called when a column is sized
01885 *************************************************************************/
01886 void MultiColumnList::onListColumnSized(WindowEventArgs& e)
01887 {
01888         configureScrollbars();
01889         requestRedraw();
01890         fireEvent(EventListColumnSized, e, EventNamespace);
01891 }
01892 
01893 
01894 /*************************************************************************
01895         Handler called when a column is moved
01896 *************************************************************************/
01897 void MultiColumnList::onListColumnMoved(WindowEventArgs& e)
01898 {
01899         requestRedraw();
01900         fireEvent(EventListColumnMoved, e, EventNamespace);
01901 }
01902 
01903 
01904 /*************************************************************************
01905         Handler for when we are sized
01906 *************************************************************************/
01907 void MultiColumnList::onSized(WindowEventArgs& e)
01908 {
01909         // base class handling
01910         Window::onSized(e);
01911 
01912         configureScrollbars();
01913 
01914         e.handled = true;
01915 }
01916 
01917 
01918 /*************************************************************************
01919         Handler for when mouse button is pressed
01920 *************************************************************************/
01921 void MultiColumnList::onMouseButtonDown(MouseEventArgs& e)
01922 {
01923         // base class processing
01924         Window::onMouseButtonDown(e);
01925 
01926         if (e.button == LeftButton)
01927         {
01928                 bool modified = false;
01929 
01930                 // clear old selections if no control key is pressed or if multi-select is off
01931                 if (!(e.sysKeys & Control) || !d_multiSelect)
01932                 {
01933                         modified = clearAllSelections_impl();
01934                 }
01935 
01936                 Point localPos(screenToWindow(e.position));
01937 
01938                 if (getMetricsMode() == Relative)
01939                 {
01940                         localPos = relativeToAbsolute(localPos);
01941                 }
01942 
01943                 ListboxItem* item = getItemAtPoint(localPos);
01944 
01945                 if (item != NULL)
01946                 {
01947                         modified = true;
01948 
01949                         // select range or item, depending upon keys and last selected item
01950                         if (((e.sysKeys & Shift) && (d_lastSelected != NULL)) && d_multiSelect)
01951                         {
01952                                 modified |= selectRange(getItemGridReference(item), getItemGridReference(d_lastSelected));
01953                         }
01954                         else
01955                         {
01956                                 modified |= setItemSelectState_impl(getItemGridReference(item), item->isSelected() ^ true);
01957                         }
01958 
01959                         // update last selected item
01960                         d_lastSelected = item->isSelected() ? item : NULL;
01961                 }
01962 
01963                 // fire event if needed
01964                 if (modified)
01965                 {
01966                         WindowEventArgs args(this);
01967                         onSelectionChanged(args);
01968                 }
01969                 
01970                 e.handled = true;
01971         }
01972 
01973 }
01974 
01975 
01976 /*************************************************************************
01977         Handler for mouse wheel changes
01978 *************************************************************************/
01979 void MultiColumnList::onMouseWheel(MouseEventArgs& e)
01980 {
01981         // base class processing.
01982         Window::onMouseWheel(e);
01983 
01984         if (d_vertScrollbar->isVisible() && (d_vertScrollbar->getDocumentSize() > d_vertScrollbar->getPageSize()))
01985         {
01986                 d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition() + d_vertScrollbar->getStepSize() * -e.wheelChange);
01987         }
01988         else if (d_horzScrollbar->isVisible() && (d_horzScrollbar->getDocumentSize() > d_horzScrollbar->getPageSize()))
01989         {
01990                 d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition() + d_horzScrollbar->getStepSize() * -e.wheelChange);
01991         }
01992 
01993         e.handled = true;
01994 }
01995 
01996 
01997 /*************************************************************************
01998         Event handler for header offset changes (scrolling)
01999 *************************************************************************/
02000 bool MultiColumnList::handleHeaderScroll(const EventArgs& e)
02001 {
02002         // grab the header scroll value, convert to pixels, and set the scroll bar to match.
02003         d_horzScrollbar->setScrollPosition(d_header->relativeToAbsoluteX(d_header->getSegmentOffset()));
02004 
02005         return true;
02006 }
02007 
02008 
02009 /*************************************************************************
02010         Event handler for drag & drop of header segments
02011 *************************************************************************/
02012 bool MultiColumnList::handleHeaderSegMove(const EventArgs& e)
02013 {
02014         moveColumn_impl(((HeaderSequenceEventArgs&)e).d_oldIdx, ((HeaderSequenceEventArgs&)e).d_newIdx);
02015 
02016         // signal change to our clients
02017         WindowEventArgs args(this);
02018         onListColumnMoved(args);
02019 
02020         return true;
02021 }
02022 
02023 
02024 
02025 /*************************************************************************
02026         Event handler for when header segment size (column width) changes
02027 *************************************************************************/
02028 bool MultiColumnList::handleColumnSizeChange(const EventArgs& e)
02029 {
02030         configureScrollbars();
02031 
02032         // signal change to our clients
02033         WindowEventArgs args(this);
02034         onListColumnSized(args);
02035 
02036         return true;
02037 }
02038 
02039 
02040 /*************************************************************************
02041         Event handler for when horizontal scroll bar is moved.
02042 *************************************************************************/
02043 bool MultiColumnList::handleHorzScrollbar(const EventArgs& e)
02044 {
02045         // set header offset to match scroll position
02046         d_header->setSegmentOffset(d_header->absoluteToRelativeX(d_horzScrollbar->getScrollPosition()));
02047     requestRedraw();
02048         return true;
02049 }
02050 
02051 /*************************************************************************
02052         Event handler for when vertical scroll bar is moved.
02053 *************************************************************************/
02054 bool MultiColumnList::handleVertScrollbar(const EventArgs& e)
02055 {
02056     requestRedraw();
02057         return true;
02058 }
02059 
02060 
02061 /*************************************************************************
02062         Handler for when sort column in header is changed
02063 *************************************************************************/
02064 bool MultiColumnList::handleSortColumnChange(const EventArgs& e)
02065 {
02066         uint col = getSortColumn();
02067 
02068         // set new sort column on all rows
02069         for (uint i = 0; i < getRowCount(); ++i)
02070         {
02071                 d_grid[i].d_sortColumn = col;
02072         }
02073 
02074         // re-sort list according to direction
02075         ListHeaderSegment::SortDirection dir = getSortDirection();
02076 
02077         if (dir == ListHeaderSegment::Descending)
02078         {
02079                 std::sort(d_grid.begin(), d_grid.end());
02080         }
02081         else if (dir == ListHeaderSegment::Ascending)
02082         {
02083                 std::sort(d_grid.begin(), d_grid.end(), pred_descend);
02084         }
02085 
02086         // else, no direction, so do not sort.
02087 
02088         // signal change to our clients
02089         WindowEventArgs args(this);
02090         onSortColumnChanged(args);
02091 
02092         return true;
02093 }
02094 
02095 
02096 /*************************************************************************
02097         Handler for when sort direction in header is changed
02098 *************************************************************************/
02099 bool MultiColumnList::handleSortDirectionChange(const EventArgs& e)
02100 {
02101         // re-sort list according to direction
02102         ListHeaderSegment::SortDirection dir = getSortDirection();
02103 
02104         if (dir == ListHeaderSegment::Descending)
02105         {
02106                 std::sort(d_grid.begin(), d_grid.end());
02107         }
02108         else if (dir == ListHeaderSegment::Ascending)
02109         {
02110                 std::sort(d_grid.begin(), d_grid.end(), pred_descend);
02111         }
02112 
02113         // else, no direction, so do not sort.
02114 
02115         // signal change to our clients
02116         WindowEventArgs args(this);
02117         onSortDirectionChanged(args);
02118 
02119         return true;
02120 }
02121 
02122 
02123 /*************************************************************************
02124         Handler for when user double-clicks on header segment splitter
02125 *************************************************************************/
02126 bool MultiColumnList::handleHeaderSegDblClick(const EventArgs& e)
02127 {
02128         // get the column index for the segment that was double-clicked
02129         uint col = d_header->getColumnFromSegment((ListHeaderSegment&)*((WindowEventArgs&)e).window);
02130 
02131         autoSizeColumnHeader(col);
02132 
02133         return true;
02134 }
02135 
02136 
02137 /*************************************************************************
02138         Set whether user manipulation of the sort column and direction are
02139         enabled.        
02140 *************************************************************************/
02141 void MultiColumnList::setUserSortControlEnabled(bool setting)
02142 {
02143         d_header->setSortingEnabled(setting);
02144 }
02145 
02146 
02147 /*************************************************************************
02148         Set whether the user may size column segments.  
02149 *************************************************************************/
02150 void MultiColumnList::setUserColumnSizingEnabled(bool setting)
02151 {
02152         d_header->setColumnSizingEnabled(setting);
02153 }
02154 
02155 
02156 /*************************************************************************
02157         Set whether the user may modify the order of the columns.       
02158 *************************************************************************/
02159 void MultiColumnList::setUserColumnDraggingEnabled(bool setting)
02160 {
02161         d_header->setColumnDraggingEnabled(setting);
02162 }
02163 
02164 
02165 /*************************************************************************
02166         Return the ID code assigned to the requested column.
02167 *************************************************************************/
02168 uint MultiColumnList::getColumnID(uint col_idx) const
02169 {
02170         return d_header->getSegmentFromColumn(col_idx).getID();
02171 }
02172 
02173 
02174 /*************************************************************************
02175         Return the ID code assigned to the requested row.
02176 *************************************************************************/
02177 uint MultiColumnList::getRowID(uint row_idx) const
02178 {
02179         // check for invalid index
02180         if (row_idx >= getRowCount())
02181         {
02182                 throw InvalidRequestException((utf8*)"MultiColumnList::getRowID - the row index given is out of range.");
02183         }
02184         else
02185         {
02186                 return d_grid[row_idx].d_rowID;
02187         }
02188 }
02189 
02190 
02191 /*************************************************************************
02192         Return the zero based row index of the row with the specified ID.
02193 *************************************************************************/
02194 uint MultiColumnList::getRowWithID(uint row_id) const
02195 {
02196         for (uint i = 0; i < getRowCount(); ++i)
02197         {
02198                 if (d_grid[i].d_rowID == row_id)
02199                 {
02200                         return i;
02201                 }
02202         }
02203 
02204         // No such row found, throw exception
02205         throw InvalidRequestException((utf8*)"MultiColumnList::getRowWithID - no row with the requested ID is present.");
02206 }
02207 
02208 
02209 /*************************************************************************
02210         std algorithm predicate used for sorting in descending order (static)
02211 *************************************************************************/
02212 bool MultiColumnList::pred_descend(const ListRow& a, const ListRow& b)
02213 {
02214         return a > b;
02215 }
02216 
02217 
02218 /*************************************************************************
02219         Return whether the vertical scroll bar is always shown.
02220 *************************************************************************/
02221 bool MultiColumnList::isVertScrollbarAlwaysShown(void) const
02222 {
02223         return d_forceVertScroll;
02224 }
02225 
02226 
02227 /*************************************************************************
02228         Return whether the horizontal scroll bar is always shown.
02229 *************************************************************************/
02230 bool MultiColumnList::isHorzScrollbarAlwaysShown(void) const
02231 {
02232         return d_forceHorzScroll;
02233 }
02234 
02235 
02236 /*************************************************************************
02237         Adds properties for MCL
02238 *************************************************************************/
02239 void MultiColumnList::addMultiColumnListProperties(void)
02240 {
02241         addProperty(&d_columnsSizableProperty);
02242         addProperty(&d_columnsMovableProperty);
02243         addProperty(&d_forceHorzScrollProperty);
02244         addProperty(&d_forceVertScrollProperty);
02245         addProperty(&d_nominatedSelectColProperty);
02246         addProperty(&d_nominatedSelectRowProperty);
02247         addProperty(&d_selectModeProperty);
02248         addProperty(&d_sortColumnIDProperty);
02249         addProperty(&d_sortDirectionProperty);
02250         addProperty(&d_sortSettingProperty);
02251         addProperty(&d_columnHeaderProperty);
02252         addProperty(&d_rowCountProperty);
02253 }
02254 
02255 
02256 /*************************************************************************
02257         Remove all items from the list.
02258 *************************************************************************/
02259 bool MultiColumnList::resetList_impl(void)
02260 {
02261         // just return false if the list is already empty (no rows == empty)
02262         if (getRowCount() == 0)
02263         {
02264                 return false;
02265         }
02266         // we have items to be removed and possible deleted
02267         else
02268         {
02269                 for (uint i = 0; i < getRowCount(); ++i)
02270                 {
02271                         for (uint j = 0; j < getColumnCount(); ++j)
02272                         {
02273                                 ListboxItem* item = d_grid[i][j];
02274 
02275                                 // delete item as needed.
02276                                 if ((item != NULL) && item->isAutoDeleted())
02277                                 {
02278                                         delete item;
02279                                 }
02280 
02281                         }
02282 
02283                 }
02284 
02285                 // clear all items from the grid.
02286                 d_grid.clear();
02287 
02288                 // reset other affected fields
02289                 d_nominatedSelectRow = 0;
02290                 d_lastSelected = NULL;
02291 
02292                 return true;
02293         }
02294 
02295 }
02296 
02297 
02298 /*************************************************************************
02299         Automatically determines the "best fit" size for the specified column
02300         and sets the column width to the same.
02301 *************************************************************************/
02302 void MultiColumnList::autoSizeColumnHeader(uint col_idx)
02303 {
02304         // check for invalid index
02305         if (col_idx >= getColumnCount())
02306         {
02307                 throw InvalidRequestException((utf8*)"MultiColumnList::isListboxItemInColumn - the column index given is out of range.");
02308         }
02309         else
02310         {
02311                 // get the width of the widest item in the column.
02312                 float width = ceguimax(getWidestColumnItemWidth(col_idx), ListHeader::MinimumSegmentPixelWidth);
02313 
02314                 // perform metrics conversion if needed
02315                 if (getMetricsMode() == Relative)
02316                 {
02317                         width = absoluteToRelativeX(width);
02318                 }
02319 
02320                 // set new column width
02321                 setColumnHeaderWidth(col_idx, width);
02322         }
02323 
02324 }
02325 
02326 
02327 /*************************************************************************
02328         Set the ID code assigned to a given row.
02329 *************************************************************************/
02330 void MultiColumnList::setRowID(uint row_idx, uint row_id)
02331 {
02332         // check for invalid index
02333         if (row_idx >= getRowCount())
02334         {
02335                 throw InvalidRequestException((utf8*)"MultiColumnList::setRowID - the row index given is out of range.");
02336         }
02337         else
02338         {
02339                 d_grid[row_idx].d_rowID = row_id;
02340         }
02341 }
02342 
02343 int MultiColumnList::writePropertiesXML(OutStream& out_stream) const
02344 {
02345     // basically this is here to translate the columns in the list into
02346     // instances of the <ColumnHeader> element.  Because the SortColumnID
02347     // property requires the column to exist, we also write that out manually.
02348 
02349     // Dump all other properties first
02350     int propCnt = Window::writePropertiesXML(out_stream);
02351 
02352     // create an dump <ColumnHeader> elements
02353     for (uint i = 0; i < getColumnCount(); ++i)
02354     {
02355         ListHeaderSegment& seg = getHeaderSegmentForColumn(i);
02356 
02357         // start of property element,
02358         String propString("<Property Name=\"ColumnHeader\" Value=\"");
02359         // column text
02360         propString += "text:";
02361         propString += seg.getText();
02362         // column width
02363         propString += " width:";
02364         propString += PropertyHelper::floatToString(seg.getRelativeWidth());
02365         // column id
02366         propString += " id:";
02367         propString += PropertyHelper::uintToString(seg.getID());
02368         // close the tag
02369         propString += "\" />";
02370 
02371         // write this out to the stream
02372         out_stream << propString.c_str() << std::endl;
02373 
02374         ++propCnt;
02375     }
02376 
02377     // write out SortColumnID property
02378     uint sortColumnID = getColumnWithID(getSortColumn());
02379     if (sortColumnID != 0)
02380     {
02381         out_stream << "<Property Name=\"SortColumnID\" Value=\"" << PropertyHelper::uintToString(sortColumnID).c_str() << "\" />" << std::endl;
02382         ++propCnt;
02383     }
02384 
02385     return propCnt;
02386 }
02387 
02388 
02390 /*************************************************************************
02391         Operators for ListRow
02392 *************************************************************************/
02394 /*************************************************************************
02395         Less-than operator
02396 *************************************************************************/
02397 bool MultiColumnList::ListRow::operator<(const ListRow& rhs) const
02398 {
02399         ListboxItem* a = d_items[d_sortColumn];
02400         ListboxItem* b = rhs.d_items[d_sortColumn];
02401 
02402         // handle cases with empty slots
02403         if (b == NULL)
02404         {
02405                 return false;
02406         }
02407         else if (a == NULL)
02408         {
02409                 return true;
02410         }
02411         else
02412         {
02413                 return a->getText() < b->getText();
02414         }
02415 
02416 }
02417 
02418 
02419 /*************************************************************************
02420         Greater-than operator
02421 *************************************************************************/
02422 bool MultiColumnList::ListRow::operator>(const ListRow& rhs) const
02423 {
02424         ListboxItem* a = d_items[d_sortColumn];
02425         ListboxItem* b = rhs.d_items[d_sortColumn];
02426 
02427         // handle cases with empty slots
02428         if (a == NULL)
02429         {
02430                 return false;
02431         }
02432         else if (b == NULL)
02433         {
02434                 return true;
02435         }
02436         else
02437         {
02438                 return a->getText() > b->getText();
02439         }
02440 
02441 }
02442 
02443 
02445 /*************************************************************************
02446         Operators for MCLGridRef
02447 *************************************************************************/
02449 /*************************************************************************
02450         Assignment operator
02451 *************************************************************************/
02452 MCLGridRef& MCLGridRef::operator=(const MCLGridRef& rhs)
02453 {
02454         column = rhs.column;
02455         row = rhs.row;
02456         return *this;
02457 }
02458 
02459 
02460 /*************************************************************************
02461         return true if this is less than (appears before) 'rhs' in grid.
02462 *************************************************************************/
02463 bool MCLGridRef::operator<(const MCLGridRef& rhs) const
02464 {
02465         if ((row < rhs.row) ||
02466                 ((row == rhs.row) && (column < rhs.column)))
02467         {
02468                 return true;
02469         }
02470         else
02471         {
02472                 return false;
02473         }
02474 }
02475 
02476 
02477 /*************************************************************************
02478         return true if this is less than or equal to 'rhs'
02479 *************************************************************************/
02480 bool MCLGridRef::operator<=(const MCLGridRef& rhs) const
02481 {
02482         return !operator>(rhs);
02483 }
02484 
02485 
02486 /*************************************************************************
02487         return true if this is greater than (appears after) 'rhs' in grid.
02488 *************************************************************************/
02489 bool MCLGridRef::operator>(const MCLGridRef& rhs) const
02490 {
02491         return (operator<(rhs) || operator==(rhs)) ? false : true;
02492 }
02493 
02494 
02495 /*************************************************************************
02496         return true if this is greater than or equal to 'rhs'
02497 *************************************************************************/
02498 bool MCLGridRef::operator>=(const MCLGridRef& rhs) const
02499 {
02500         return !operator<(rhs);
02501 }
02502 
02503 
02504 /*************************************************************************
02505         return true if this grid ref is equal to that in 'rhs'
02506 *************************************************************************/
02507 bool MCLGridRef::operator==(const MCLGridRef& rhs) const
02508 {
02509         return ((column == rhs.column) && (row == rhs.row)) ? true : false;
02510 }
02511 
02512 
02513 /*************************************************************************
02514         return true if this grid ref is different to that in 'rhs'
02515 *************************************************************************/
02516 bool MCLGridRef::operator!=(const MCLGridRef& rhs) const
02517 {
02518         return !operator==(rhs);
02519 }
02520 
02521 } // End of  CEGUI namespace section

Generated on Wed Sep 7 09:56:32 2005 for Crazy Eddies GUI System by  doxygen 1.4.3