00001
00002 #ifndef MediaTable_TableDataView_h
00003 #define MediaTable_TableDataView_h
00004
00005 #include "TableColumn.h"
00006 #include "TableDataSourceListener.h"
00007 #include "TableDataViewListener.h"
00008 #include "Core/Array/Arrays.h"
00009 #include "TableFilter.h"
00010
00011 #include "TableDataSource.h"
00012
00013 namespace Impala {
00014 namespace Application {
00015 namespace MediaTable {
00016
00017
00018 bool compare_string_nocase (std::pair<String, int> a, std::pair<String, int> b)
00019 {
00020 unsigned int i=0;
00021 String first = a.first;
00022 String second = b.first;
00023 while ( (i < first.length()) && (i < second.length()) )
00024 {
00025 if (tolower(first[i])<tolower(second[i]))
00026 return true;
00027 else if (tolower(first[i])>tolower(second[i]))
00028 return false;
00029 ++i;
00030 }
00031 return first.length() < second.length();
00032 };
00033
00034
00035 bool compare_double (std::pair<double, int> a, std::pair<double, int> b)
00036 {
00037 return a.first < b.first;
00038 };
00039
00040
00041 bool compare_int (std::pair<int, int> a, std::pair<int, int> b)
00042 {
00043 return a.first < b.first;
00044 };
00045
00046 class TableDataView : public TableFilterUpdateListener,
00047 public TableDataSourceListener
00048 {
00049 typedef Impala::Core::Array::Array2dVec3UInt8 Array2dVec3UInt8;
00050 typedef std::vector<TableColumn*> TableColumnVector;
00051
00052 public:
00053 TableDataView()
00054 {
00055 TableDataView(0);
00056 }
00057
00058 TableDataView(TableDataSource* table)
00059 {
00060 mTableDataSource = table;
00061
00062 mDisplayRows = 50;
00063 mFilteredRows = 1000;
00064 mStartRow = 0;
00065 mSortType = 1;
00066 mSortColumn = "";
00067 mSortAscending = true;
00068 mFiltersWorking = false;
00069 mFiltersActive = false;
00070 mFilterByMark = -1;
00071
00072
00073 TableColumnVector::iterator it;
00074
00075 if(mTableDataSource)
00076 {
00077 mTableDataSource->AddTableDataSourceListener(this);
00078 TableColumnVector columns =
00079 mTableDataSource->GetColumns(true, false);
00080 for ( it = columns.begin() ; it < columns.end(); it++ )
00081 {
00082 if((*it)->GetType() != TableDataSource::TYPE_FLAG_IMAGE)
00083 {
00084 SetSortColumn((*it)->GetName());
00085 break;
00086 }
00087 }
00088 }
00089 }
00090
00091 virtual void UpdateRowsEvent()
00092 {
00093 ILOG_DEBUG("TableDataView: UpdateRowsEvent");
00094 if (GetListenTableUpdates())
00095 DoUpdateRowsEvent();
00096 }
00097
00098 virtual void UpdateNumberOfRowsEvent()
00099 {
00100 DoUpdateNumberOfRowsEvent();
00101 }
00102
00103 int GetTotalRows()
00104 {
00105 return mTableDataSource->GetTotalRows();
00106 }
00107
00108 int GetFilteredRows()
00109 {
00110
00111 return mFilteredRows;
00112 }
00113
00114
00115 int GetStartRow()
00116 {
00117 return mStartRow;
00118 }
00119
00120 int GetEndRow()
00121 {
00122 return GetStartRow() + GetNumberOfRows();
00123 }
00124
00125 int GetNumberOfRows()
00126 {
00127 if (mDisplayRows > mFilteredRows - GetStartRow())
00128 return mFilteredRows - GetStartRow();
00129 return mDisplayRows;
00130 }
00131
00132
00133
00134 inline int GetMark(int sortedrow)
00135 {
00136 int row = mSortSequence[sortedrow];
00137 if(mMarkedRows.find(row) != mMarkedRows.end())
00138 return mMarkedRows[row];
00139 return 0;
00140 }
00141
00142 inline int GetMarkById(int id)
00143 {
00144 if(mMarkedRows.find(id) != mMarkedRows.end())
00145 return mMarkedRows[id];
00146 return 0;
00147 }
00148
00149 inline void SetMark(int sortedrow, int mark)
00150 {
00151 mMarkedRows[mSortSequence[sortedrow]] = mark;
00152 }
00153
00154 inline void SetMarkById(int id, int mark)
00155 {
00156 mMarkedRows[id] = mark;
00157 }
00158
00159 inline void MarkAllRows(int mask, bool mark=true)
00160 {
00161 for(int id=0; id < GetTotalRows(); id++)
00162 {
00163 if (mark)
00164 SetMarkById(id, GetMarkById(id) | mask);
00165 else
00166 SetMarkById(id, GetMarkById(id) & ~mask);
00167 }
00168 }
00169
00170
00171 inline std::map<int, int>
00172 GetMarkedRowsMap()
00173 {
00174 return mMarkedRows;
00175 }
00176
00177 void
00178 MarkRow(int sortedrow, int markstate, bool mark=true, bool toggle=false)
00179 {
00180 if(sortedrow >= mSortSequence.size())
00181 return;
00182 int row = mSortSequence[sortedrow];
00183 if (row < 0 || row > GetTotalRows())
00184 return;
00185 if (mark)
00186 {
00187 if(mMarkedRows.find(row) == mMarkedRows.end())
00188 mMarkedRows[row] = markstate;
00189 else if (toggle)
00190 mMarkedRows[row] = mMarkedRows[row] ^ markstate;
00191 else
00192 mMarkedRows[row] = mMarkedRows[row] | markstate;
00193 }
00194 else if(mMarkedRows.find(row) != mMarkedRows.end())
00195 mMarkedRows[row] = mMarkedRows[row] & ~markstate;
00196
00197
00198
00199 }
00200
00201 inline void MarkAllFilteredRows(int markstate, bool mark=true)
00202 {
00203 MarkRange(0, GetFilteredRows()-1, markstate, mark);
00204 }
00205
00206 void MarkRange(int start, int stop, int markstate, bool mark=true)
00207 {
00208 if (stop <= start)
00209 {
00210 int t = stop;
00211 stop = start;
00212 start = t;
00213 }
00214 if (start < 0)
00215 start = 0;
00216
00217 if (stop >= GetFilteredRows())
00218 stop = GetFilteredRows()-1;
00219
00220 for (int i=start; i<=stop; i++)
00221 MarkRow(i, markstate, mark);
00222 }
00223
00224 void TransformMarkedTo(int sourcemask, int targetmask)
00225 {
00226 for (int i=0; i<GetTotalRows(); i++)
00227 {
00228 if(mMarkedRows.find(i) != mMarkedRows.end())
00229 {
00230 if (mMarkedRows[i] & sourcemask)
00231 {
00232 mMarkedRows[i] = mMarkedRows[i] & ~sourcemask;
00233 mMarkedRows[i] = mMarkedRows[i] | targetmask;
00234 }
00235 }
00236 }
00237 }
00238
00239 void SetStartRowToFirstMarked(int mark)
00240 {
00241 for(int row=0; row < GetFilteredRows(); row++)
00242 {
00243 if(GetMark(row) & mark)
00244 {
00245 SetStartRow(row);
00246 return;
00247 }
00248 }
00249 }
00250
00251
00252
00253 void SetStartRow(int startrow)
00254 {
00255 if (startrow >= 0 && startrow < GetTotalRows() && startrow != mStartRow)
00256 {
00257 ILOG_DEBUG("SetStartRow( " << startrow << ")");
00258 mStartRow = startrow;
00259 DoUpdateScrollFromSourceEvent();
00260 DoUpdateRowsEvent();
00261 }
00262 }
00263
00264 void SetNumberOfRows(int number)
00265 {
00266 if (number > 0 && number != mDisplayRows)
00267 {
00268 ILOG_DEBUG("SetNumberOfRows(" << number << ")");
00269 mDisplayRows = number;
00270 DoUpdateRowsEvent();
00271 }
00272 }
00273
00274 bool OutOfBounds(int row)
00275 {
00276 if (row < GetStartRow() || row >= GetStartRow() + GetNumberOfRows())
00277 return true;
00278 return false;
00279 }
00280
00281 bool OutOfBoundsByID(int id)
00282 {
00283 return OutOfBounds(GetRowForID(id));
00284 }
00285
00286 bool OutOfBoundsByQuid(unsigned long long quid)
00287 {
00288 return OutOfBoundsByID(mTableDataSource->GetIDForQuid(quid));
00289 }
00290
00291
00292
00293 String GetSortColumn()
00294 {
00295 return mSortColumn;
00296 }
00297
00298 bool GetSortAscending()
00299 {
00300 return mSortAscending;
00301 }
00302
00303
00304
00305 std::map<int, bool>
00306 GetUnfilteredRowsMap()
00307 {
00308 return mVisibleRows;
00309 }
00310
00311 virtual void ApplyFilters()
00312 {
00313 SortAndFilter();
00314 }
00315
00316 virtual void SortAndFilter()
00317 {
00318 ILOG_DEBUG("re-sorting to " << mSortColumn << "/" << mSortAscending);
00319 mVisibleRows.clear();
00320 mSortType = GetColumn(mSortColumn)->GetType();
00321 if (mSortType == TableDataSource::TYPE_TEXT)
00322 SortAndFilterText();
00323 if (mSortType & TableDataSource::TYPE_FLAG_FLOAT)
00324 SortAndFilterFloat();
00325 if (mSortType == TableDataSource::TYPE_INT)
00326 SortAndFilterInt();
00327 ILOG_DEBUG("sorting completed.");
00328 DoUpdateSortEvent();
00329 DoUpdateSelectionEvent();
00330 DoUpdateRowsEvent();
00331 }
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430 void SetSortColumn(String column, bool ascending=true)
00431 {
00432 if (mSortColumn != column || mSortAscending != ascending)
00433 {
00434 mSortColumn = column;
00435 mSortAscending = ascending;
00436 SortAndFilter();
00437 }
00438 }
00439
00440
00441 void AddTableDataViewListener(TableDataViewListener* l)
00442 {
00443 mTableListeners.push_back(l);
00444 }
00445
00446
00447
00448 void DoUpdateRowsEvent()
00449 {
00450 for (int i=0; i< mTableListeners.size(); i++)
00451 if (mTableListeners[i]->GetListenTableUpdates())
00452 mTableListeners[i]->UpdateRowsEvent();
00453 }
00454
00455 void DoUpdateNumberOfRowsEvent()
00456 {
00457 for (int i=0; i< mTableListeners.size(); i++)
00458 if (mTableListeners[i]->GetListenTableUpdates())
00459 mTableListeners[i]->UpdateNumberOfRowsEvent();
00460 }
00461
00462 void DoUpdateSelectionEvent()
00463 {
00464 for (int i=0; i< mTableListeners.size(); i++)
00465 if (mTableListeners[i]->GetListenTableUpdates())
00466 mTableListeners[i]->UpdateSelectionEvent();
00467 }
00468
00469
00470 void DoUpdateSortEvent()
00471 {
00472 for (int i=0; i< mTableListeners.size(); i++)
00473 if (mTableListeners[i]->GetListenTableUpdates())
00474 mTableListeners[i]->UpdateSortEvent(mSortColumn,mSortAscending);
00475 }
00476
00477 void DoUpdateScrollFromSourceEvent()
00478 {
00479 ILOG_DEBUG("DoUpdateScrollFromSourceEvent");
00480 for (int i=0; i< mTableListeners.size(); i++)
00481 if (mTableListeners[i]->GetListenTableUpdates())
00482 mTableListeners[i]->UpdateScrollFromSourceEvent();
00483 }
00484
00485
00486
00487 inline double
00488 GetNormalizedDataByID(String column, int id)
00489 {
00490 return mTableDataSource->GetNormalizedDataByID(column, id);
00491 }
00492
00493 inline int
00494 GetIntDataByID(String column, int id)
00495 {
00496 return mTableDataSource->GetIntDataByID(column, id);
00497 }
00498
00499 inline String
00500 GetTextDataByID(String column, int id)
00501 {
00502 return mTableDataSource->GetTextDataByID(column, id);
00503 }
00504
00505 inline double
00506 GetDoubleDataByID(String column, int id)
00507 {
00508 return mTableDataSource->GetDoubleDataByID(column, id);
00509 }
00510
00511 inline String
00512 GetSortedTextData(String column, int row)
00513 {
00514 return mTableDataSource->GetTextDataByID(column, mSortSequence[row]);
00515 }
00516
00517 inline double
00518 GetSortedNormalizedData(String column, int row)
00519 {
00520 return mTableDataSource->
00521 GetNormalizedDataByID(column, mSortSequence[row]);
00522 }
00523
00524 inline Array2dVec3UInt8*
00525 GetSortedImageData(String column, int row)
00526 {
00527 return mTableDataSource->GetImageDataByID(column, mSortSequence[row]);
00528 }
00529
00530 inline Array2dVec3UInt8*
00531 GetSortedVideoData(String column, int row)
00532 {
00533 return mTableDataSource->GetVideoDataByID(column, mSortSequence[row]);
00534 }
00535
00536 inline int
00537 GetSortedIntData(String column, int row)
00538 {
00539 return mTableDataSource->GetIntDataByID(column, mSortSequence[row]);
00540 }
00541
00542 inline double
00543 GetSortedDoubleData(String column, int row)
00544 {
00545 return mTableDataSource->GetDoubleDataByID(column, mSortSequence[row]);
00546 }
00547
00548 inline unsigned long long
00549 GetSortedQuid(String column, int row) {
00550 return mTableDataSource->GetQuid(column, mSortSequence[row]);
00551 }
00552
00553 int GetID(int row)
00554 {
00555 if (row >= 0 && row < GetTotalRows() && row < mSortSequence.size())
00556 return mSortSequence[row];
00557 else
00558 return -1;
00559 }
00560
00561 int GetRowForID(int id)
00562 {
00563 int size = mSortSequence.size();
00564 for (int i=0; i<GetTotalRows() && i<size; i++)
00565 if (mSortSequence[i] == id)
00566 return i;
00567 return -1;
00568 }
00569
00570
00571 void RemoveFilter(String column)
00572 {
00573 std::list<TableFilter*>::iterator it;
00574 for (it=mFilters.begin(); it!=mFilters.end(); it++)
00575 {
00576 if ((*it)->GetColumn() == column)
00577 mFilters.erase(it);
00578
00579 if (mFilters.size() == 0)
00580 mFiltersActive = false;
00581
00582
00583 if (!mFiltersWorking)
00584 ApplyFilters();
00585 break;
00586 }
00587 }
00588
00589 void RegisterFilter(TableFilter *t)
00590 {
00591 mFiltersWorking = true;
00592 RemoveFilter(t->GetColumn());
00593 mFiltersWorking = false;
00594 mFilters.push_back(t);
00595 mFiltersActive = true;
00596
00597 }
00598
00599 void EnableFilterByMark(int mark)
00600 {
00601 ILOG_DEBUG("Enable filter by mark for mark=" << mark);
00602 mFilterByMark = mark;
00603 ApplyFilters();
00604 }
00605
00606 int GetMarkFilter()
00607 {
00608 return mFilterByMark;
00609 }
00610
00611 int GetMarkFilterForEverything()
00612 {
00613 return 4|8|16|32|64|128;
00614 }
00615
00616 void DisableFilterByMark()
00617 {
00618 ILOG_DEBUG("Filter by mark disabled");
00619 mFilterByMark = -1;
00620 ApplyFilters();
00621 }
00622
00623 TableColumnVector
00624 GetColumns(bool StaticColumns=true, bool ExtraColumns=false)
00625 {
00626 return mTableDataSource->GetColumns(StaticColumns, ExtraColumns);
00627 }
00628
00629 TableColumn* GetColumn(std::string column)
00630 {
00631 return mTableDataSource->GetColumn(column);
00632 }
00633
00634 private:
00635
00636 bool IsFiltered(int id)
00637 {
00638
00639 if (mFilterByMark > -1)
00640 {
00641 if (mMarkedRows.find(id) != mMarkedRows.end())
00642 {
00643 if (!(mMarkedRows[id] & mFilterByMark))
00644 return true;
00645 }
00646 else if (mFilterByMark != 0)
00647 return true;
00648 }
00649
00650
00651 if (!mFiltersActive)
00652 return false;
00653
00654 std::list<TableFilter*>::iterator it;
00655 for (it=mFilters.begin(); it!=mFilters.end(); it++)
00656 {
00657
00658
00659
00660
00661
00662 if ((*it)->GetType() == 1)
00663 {
00664 String txt = GetTextDataByID((*it)->GetColumn(), id);
00665 if ((*it)->IsFilteredByText(txt))
00666 return true;
00667 }
00668 else if ((*it)->GetType() == 2)
00669 {
00670 switch(GetColumn((*it)->GetColumn())->GetType())
00671 {
00672 double dVal;
00673 case TableDataSource::TYPE_NORMALIZEDVALUE:
00674 dVal = GetNormalizedDataByID((*it)->GetColumn(),id);
00675 if ((*it)->IsFilteredByValue(dVal))
00676 return true;
00677 break;
00678 case TableDataSource::TYPE_DOUBLE:
00679 dVal = GetDoubleDataByID((*it)->GetColumn(),id);
00680 if ((*it)->IsFilteredByValue(dVal))
00681 return true;
00682 break;
00683 case TableDataSource::TYPE_INT:
00684 int iVal = GetIntDataByID((*it)->GetColumn(),id);
00685
00686 if ((*it)->IsFilteredByValue(iVal))
00687 return true;
00688 break;
00689 }
00690 }
00691 }
00692 return false;
00693 }
00694
00695 protected:
00696 void SortAndFilterText()
00697 {
00698 std::list < std::pair <String, int> > sortthis;
00699 for (int i=0; i<mTableDataSource->GetTotalRows(); i++)
00700 {
00701 if (!IsFiltered(i))
00702 {
00703 String txt = GetTextDataByID(mSortColumn, i);
00704 sortthis.push_back( std::make_pair(txt, i) );
00705 mVisibleRows[i] = true;
00706 }
00707 else
00708 mVisibleRows[i] = false;
00709 }
00710 mFilteredRows = sortthis.size();
00711 sortthis.sort(compare_string_nocase);
00712 ILOG_DEBUG("filtered # of rows: " << mFilteredRows);
00713
00714 if (!mSortAscending)
00715 sortthis.reverse();
00716 mSortSequence.clear();
00717
00718 std::list<std::pair <String, int> >::iterator it;
00719 for (it=sortthis.begin(); it!=sortthis.end(); ++it)
00720 mSortSequence.push_back(it->second);
00721 }
00722
00723 void SortAndFilterFloat()
00724 {
00725 std::list < std::pair <double, int> > sortthis;
00726 for (int i=0; i<mTableDataSource->GetTotalRows(); i++)
00727 {
00728 if (!IsFiltered(i))
00729 {
00730 double dVal;
00731 if (mSortType == TableDataSource::TYPE_NORMALIZEDVALUE)
00732 dVal = GetNormalizedDataByID(mSortColumn,i);
00733 else
00734 dVal = GetDoubleDataByID(mSortColumn, i);
00735 sortthis.push_back( std::make_pair(dVal, i) );
00736 mVisibleRows[i] = true;
00737 }
00738 else
00739 mVisibleRows[i] = false;
00740 }
00741 mFilteredRows = sortthis.size();
00742 sortthis.sort(compare_double);
00743 ILOG_DEBUG("filtered # of rows: " << mFilteredRows);
00744
00745 bool normType = (mSortType == TableDataSource::TYPE_NORMALIZEDVALUE);
00746 bool dblType = (mSortType == TableDataSource::TYPE_DOUBLE);
00747 if ((normType && mSortAscending) || (dblType && !mSortAscending))
00748 sortthis.reverse();
00749 mSortSequence.clear();
00750
00751 std::list<std::pair <double, int> >::iterator it;
00752 for (it=sortthis.begin(); it!=sortthis.end(); ++it)
00753 mSortSequence.push_back(it->second);
00754 }
00755
00756 void SortAndFilterInt()
00757 {
00758 std::list < std::pair <int, int> > sortthis;
00759 for (int i=0; i<mTableDataSource->GetTotalRows();i++)
00760 {
00761 if (!IsFiltered(i))
00762 {
00763 int iVal = GetIntDataByID(mSortColumn, i);
00764 sortthis.push_back( std::make_pair(iVal, i) );
00765 mVisibleRows[i] = true;
00766 }
00767 else
00768 mVisibleRows[i] = false;
00769 }
00770 mFilteredRows = sortthis.size();
00771 sortthis.sort(compare_int);
00772 ILOG_DEBUG("filtered # of rows: " << mFilteredRows);
00773
00774 if (!mSortAscending)
00775 sortthis.reverse();
00776 mSortSequence.clear();
00777
00778 std::list<std::pair <int, int> >::iterator it;
00779 for (it=sortthis.begin(); it!=sortthis.end(); ++it)
00780 mSortSequence.push_back(it->second);
00781 }
00782
00783 int mFilteredRows;
00784
00785 private:
00786 bool mFiltersActive;
00787 bool mFiltersWorking;
00788 bool mSortAscending;
00789
00790 int mStartRow;
00791 int mDisplayRows;
00792 int mSortType;
00793 int mFilterByMark;
00794
00795 String mSortColumn;
00796
00797 TableDataSource* mTableDataSource;
00798 std::vector<TableDataViewListener*> mTableListeners;
00799 std::list<TableFilter*> mFilters;
00800 std::vector<int> mSortSequence;
00801
00802
00803 std::map<int, int> mMarkedRows;
00804 std::map<int, bool> mVisibleRows;
00805
00806 ILOG_VAR_DEC;
00807 };
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832 ILOG_VAR_INIT(TableDataView, Application.MediaTable);
00833
00834 }
00835 }
00836 }
00837
00838 #endif // TableDataView_h