00001 #ifndef VideoExcel_TableDataSource_h
00002 #define VideoExcel_TableDataSource_h
00003
00004 #include "TableUpdateListener.h"
00005 #include "Core/Array/Arrays.h"
00006 #include "TableFilter.h"
00007 #include "TableSourceColumnDescription.h"
00008
00009 namespace Impala {
00010 namespace Application {
00011 namespace VideoExcel {
00012
00013
00014
00015 bool compare_string_nocase (std::pair<String, int> a, std::pair<String, int> b)
00016 {
00017 unsigned int i=0;
00018 String first = a.first;
00019 String second = b.first;
00020 while ( (i<first.length()) && (i<second.length()) )
00021 {
00022 if (tolower(first[i])<tolower(second[i])) return true;
00023 else if (tolower(first[i])>tolower(second[i])) return false;
00024 ++i;
00025 }
00026 if (first.length()<second.length()) return true;
00027 else return false;
00028 };
00029
00030
00031 bool compare_double (std::pair<double, int> a, std::pair<double, int> b)
00032 {
00033 if (a.first < b.first)
00034 return true;
00035 return false;
00036 };
00037
00038
00039 bool compare_int (std::pair<int, int> a, std::pair<int, int> b)
00040 {
00041 if (a.first < b.first)
00042 return true;
00043 return false;
00044 };
00045
00046 class TableDataSource : public TableFilterUpdateListener
00047 {
00048 public:
00049 typedef Impala::Core::Array::Array2dVec3UInt8 Array2dVec3UInt8;
00050
00051 static const int TYPE_TEXT = 1;
00052 static const int TYPE_NORMALIZEDVALUE = 2;
00053 static const int TYPE_IMAGE = 3;
00054 static const int TYPE_INT = 4;
00055 static const int TYPE_DOUBLE = 5;
00056
00057 TableDataSource()
00058 {
00059 mDisplayRows = 50;
00060 mTotalRows = 1000;
00061 mFilteredRows = 1000;
00062 mStartRow = 0;
00063 mDefaultRowHeight = 20;
00064 mDefaultRowZoomHeight = 80;
00065 mSortType = 1;
00066 mZoomRow = -1;
00067 mSortColumn = "";
00068 mSortAscending = true;
00069 mFiltersWorking = false;
00070 mFiltersActive = false;
00071 }
00072
00073 int GetTotalRows()
00074 {
00075 return mTotalRows;
00076 }
00077
00078 int GetFilteredRows()
00079 {
00080 return mFilteredRows;
00081 }
00082
00083 void SetStartRow(int startrow)
00084 {
00085 if (startrow >= 0 && startrow < GetTotalRows() && startrow!=mStartRow)
00086 {
00087 mStartRow = startrow;
00088 DoUpdateRowsEvent();
00089 }
00090 }
00091
00092 void SetNumberOfRows(int number)
00093 {
00094 if (number > 0 && number != mDisplayRows)
00095 {
00096 ILOG_DEBUG("SetNumberOfRows(" << number << ")");
00097 mDisplayRows = number;
00098 DoUpdateRowsEvent();
00099 }
00100 }
00101
00102 void SetNumberOfRowsInPixels(int pixels)
00103 {
00104 if (pixels <= 0)
00105 return;
00106
00107 int yoff = 0;
00108 int rows = 0;
00109 for (int i=GetStartRow(); i<GetTotalRows(); i++)
00110 {
00111 if ((yoff += GetRowHeight(i)) > pixels)
00112 break;
00113 rows++;
00114 }
00115 if (rows != mDisplayRows)
00116 {
00117 ILOG_DEBUG("SetNumberOfRowsInPixels: " << pixels << " yields " <<
00118 rows << " rows.");
00119 SetNumberOfRows(rows);
00120 }
00121 }
00122
00123
00124
00125 int GetMark(int sortedrow)
00126 {
00127 int row = mSortSequence[sortedrow];
00128 if(mMarkedRows.find(row) != mMarkedRows.end())
00129 return mMarkedRows[row];
00130 return 0;
00131 }
00132
00133
00134 std::map<int, int>
00135 GetMarkedRowsMap()
00136 {
00137 return mMarkedRows;
00138 }
00139
00140 void
00141 MarkRow(int sortedrow, int markstate, bool mark=true, bool toggle=false)
00142 {
00143 int row = mSortSequence[sortedrow];
00144 if (row < 0 || row > GetTotalRows())
00145 return;
00146 if (mark)
00147 {
00148 if(mMarkedRows.find(row) == mMarkedRows.end())
00149 mMarkedRows[row] = markstate;
00150 else if (toggle)
00151 mMarkedRows[row] = mMarkedRows[row] ^ markstate;
00152 else
00153 mMarkedRows[row] = mMarkedRows[row] | markstate;
00154 }
00155 else if(mMarkedRows.find(row) != mMarkedRows.end())
00156 mMarkedRows[row] = mMarkedRows[row] & ~markstate;
00157
00158
00159
00160 }
00161
00162 void MarkVisibleRows(int markstate, bool mark=true)
00163 {
00164 MarkRange(GetStartRow(), GetEndRow(), markstate, mark);
00165 }
00166
00167 void MarkAllRows(int markstate, bool mark=true)
00168 {
00169 MarkRange(0, GetTotalRows(), markstate, mark);
00170 }
00171
00172 void MarkRange(int start, int stop, int markstate, bool mark=true)
00173 {
00174 if (stop <= start)
00175 {
00176 int t = stop;
00177 stop = start;
00178 start = t;
00179 }
00180 if (start < 0) start = 0;
00181 if (stop >= GetEndRow()) stop = GetEndRow()-1;
00182
00183 for (int i=start; i<=stop; i++)
00184 MarkRow(i, markstate, mark);
00185 }
00186
00187 void TransformMarkedTo(int sourcemask, int targetmask)
00188 {
00189 for (int i=0; i<GetTotalRows(); i++)
00190 {
00191 if(mMarkedRows.find(i) != mMarkedRows.end())
00192 {
00193 if (mMarkedRows[i] & sourcemask)
00194 {
00195 mMarkedRows[i] = mMarkedRows[i] & ~sourcemask;
00196 mMarkedRows[i] = mMarkedRows[i] | targetmask;
00197 }
00198 }
00199 }
00200 }
00201
00202
00203 void SetZoomRow(int row)
00204 {
00205 if (row == mZoomRow)
00206 return;
00207 if (OutOfBounds(row))
00208 return;
00209 if (mZoomRow == -1)
00210 DoUpdateNumberOfRowsEvent();
00211 mZoomRow = row;
00212 DoUpdateRowsEvent();
00213 }
00214
00215 void UnsetZoom()
00216 {
00217 if (mZoomRow == -1)
00218 return;
00219 mZoomRow = -1;
00220 DoUpdateNumberOfRowsEvent();
00221 DoUpdateRowsEvent();
00222 }
00223
00224 void SetDefaultRowSizes(int unzoom, int zoom)
00225 {
00226 mDefaultRowHeight = unzoom;
00227 mDefaultRowZoomHeight = zoom;
00228 DoUpdateNumberOfRowsEvent();
00229 DoUpdateRowsEvent();
00230 }
00231
00232
00233 int GetStartRow()
00234 {
00235 return mStartRow;
00236 }
00237
00238 int GetEndRow()
00239 {
00240 return GetStartRow() + GetNumberOfRows();
00241 }
00242
00243 int GetNumberOfRows()
00244 {
00245 if (mDisplayRows > mFilteredRows - GetStartRow())
00246 return mFilteredRows - GetStartRow();
00247 return mDisplayRows;
00248 }
00249
00250 bool OutOfBounds(int row)
00251 {
00252 if (row < GetStartRow() || row > GetStartRow() + GetNumberOfRows())
00253 return true;
00254 return false;
00255 }
00256
00257 bool OutOfBoundsByID(int id)
00258 {
00259 return OutOfBounds(GetRowForID(id));
00260 }
00261
00262
00263
00264 String GetSortColumn()
00265 {
00266 return mSortColumn;
00267 }
00268
00269 bool GetSortAscending()
00270 {
00271 return mSortAscending;
00272 }
00273
00274
00275
00276
00277 std::map<int, bool>
00278 GetVisibleRowsMap()
00279 {
00280 return mVisibleRows;
00281 }
00282
00283 void SortAndFilter()
00284 {
00285 ILOG_DEBUG("re-sorting to " << mSortColumn << "/" << mSortAscending);
00286 mVisibleRows.clear();
00287 if (mSortType == TYPE_TEXT)
00288 {
00289 std::list < std::pair <String, int> > sortthis;
00290 for (int i=0; i<GetTotalRows();i++)
00291 {
00292 if (!IsFiltered(i))
00293 {
00294 String txt = GetTextDataByID(mSortColumn, i);
00295 sortthis.push_back( std::make_pair(txt, i) );
00296 mVisibleRows[i] = true;
00297 }
00298 else
00299 mVisibleRows[i] = false;
00300 }
00301 mFilteredRows = sortthis.size();
00302 sortthis.sort(compare_string_nocase);
00303 ILOG_DEBUG("filtered # of rows: " << mFilteredRows);
00304
00305 if (!mSortAscending)
00306 sortthis.reverse();
00307 mSortSequence.clear();
00308
00309 std::list<std::pair <String, int> >::iterator it;
00310 for (it=sortthis.begin(); it!=sortthis.end(); ++it)
00311 mSortSequence.push_back(it->second);
00312 }
00313 if (mSortType == TYPE_NORMALIZEDVALUE || mSortType == TYPE_DOUBLE)
00314 {
00315 std::list < std::pair <double, int> > sortthis;
00316 for (int i=0; i<GetTotalRows();i++)
00317 {
00318 if (!IsFiltered(i))
00319 {
00320 double dVal;
00321 if (mSortType == TYPE_NORMALIZEDVALUE)
00322 dVal = GetNormalizedDataByID(mSortColumn, i);
00323 else
00324 dVal = GetDoubleDataByID(mSortColumn, i);
00325 sortthis.push_back( std::make_pair(dVal, i) );
00326 mVisibleRows[i] = true;
00327 }
00328 else
00329 mVisibleRows[i] = false;
00330 }
00331 mFilteredRows = sortthis.size();
00332 sortthis.sort(compare_double);
00333 ILOG_DEBUG("filtered # of rows: " << mFilteredRows);
00334
00335 if (mSortAscending)
00336 sortthis.reverse();
00337 mSortSequence.clear();
00338
00339 std::list<std::pair <double, int> >::iterator it;
00340 for (it=sortthis.begin(); it!=sortthis.end(); ++it)
00341 mSortSequence.push_back(it->second);
00342 }
00343 if (mSortType == TYPE_INT)
00344 {
00345 std::list < std::pair <int, int> > sortthis;
00346 for (int i=0; i<GetTotalRows();i++)
00347 {
00348 if (!IsFiltered(i))
00349 {
00350 int iVal = GetIntDataByID(mSortColumn, i);
00351 sortthis.push_back( std::make_pair(iVal, i) );
00352 mVisibleRows[i] = true;
00353 }
00354 else
00355 mVisibleRows[i] = false;
00356 }
00357 mFilteredRows = sortthis.size();
00358 sortthis.sort(compare_int);
00359 ILOG_DEBUG("filtered # of rows: " << mFilteredRows);
00360
00361 if (mSortAscending)
00362 sortthis.reverse();
00363 mSortSequence.clear();
00364
00365 std::list<std::pair <int, int> >::iterator it;
00366 for (it=sortthis.begin(); it!=sortthis.end(); ++it)
00367 mSortSequence.push_back(it->second);
00368 }
00369 ILOG_DEBUG("sorting completed.");
00370 DoUpdateSortEvent();
00371 DoUpdateSelectionEvent();
00372 DoUpdateRowsEvent();
00373 }
00374
00375 void SetSortColumn(String column, int type, bool ascending=true)
00376 {
00377 if (mSortColumn != column || mSortAscending != ascending)
00378 {
00379 mSortColumn = column;
00380 mSortAscending = ascending;
00381 mSortType = type;
00382 SortAndFilter();
00383 }
00384 }
00385
00386
00387 void AddTableUpdateListener(TableUpdateListener* l)
00388 {
00389 mTableListeners.push_back(l);
00390 }
00391
00392 void DoUpdateRowsEvent()
00393 {
00394 for (int i=0; i< mTableListeners.size(); i++)
00395 if (mTableListeners[i]->GetListenTableUpdates())
00396 mTableListeners[i]->UpdateRowsEvent();
00397 }
00398
00399 void DoUpdateNumberOfRowsEvent()
00400 {
00401 for (int i=0; i< mTableListeners.size(); i++)
00402 if (mTableListeners[i]->GetListenTableUpdates())
00403 mTableListeners[i]->UpdateNumberOfRowsEvent();
00404 }
00405
00406 void DoUpdateSelectionEvent()
00407 {
00408 for (int i=0; i< mTableListeners.size(); i++)
00409 if (mTableListeners[i]->GetListenTableUpdates())
00410 mTableListeners[i]->UpdateSelectionEvent();
00411 }
00412
00413
00414 void DoUpdateSortEvent()
00415 {
00416 for (int i=0; i< mTableListeners.size(); i++)
00417 if (mTableListeners[i]->GetListenTableUpdates())
00418 mTableListeners[i]->UpdateSortEvent(mSortColumn, mSortAscending);
00419 }
00420
00421 void DoUpdateScrollFromSourceEvent()
00422 {
00423 for (int i=0; i< mTableListeners.size(); i++)
00424 if (mTableListeners[i]->GetListenTableUpdates())
00425 mTableListeners[i]->UpdateScrollFromSourceEvent();
00426 }
00427
00428
00429
00430 inline String
00431 GetSortedTextData(String column, int row)
00432 {
00433 if (column=="rank")
00434 {
00435 std::ostringstream s;
00436 s << row;
00437 return s.str();
00438 }
00439 return GetTextDataByID(column, mSortSequence[row]);
00440 }
00441
00442 inline double
00443 GetSortedNormalizedData(String column, int row)
00444 {
00445 return GetNormalizedDataByID(column, mSortSequence[row]);
00446 }
00447
00448 inline Array2dVec3UInt8*
00449 GetSortedImageData(String column, int row)
00450 {
00451 return GetImageDataByID(column, mSortSequence[row]);
00452 }
00453
00454 inline Array2dVec3UInt8*
00455 GetSortedVideoData(String column, int row)
00456 {
00457 return GetVideoDataByID(column, mSortSequence[row]);
00458 }
00459
00460 inline int
00461 GetSortedIntData(String column, int row)
00462 {
00463 return GetIntDataByID(column, mSortSequence[row]);
00464 }
00465
00466 inline double
00467 GetSortedDoubleData(String column, int row)
00468 {
00469 return GetDoubleDataByID(column, mSortSequence[row]);
00470 }
00471
00472
00473 virtual int GetRowHeight(int row)
00474 {
00475 if (mZoomRow > -1)
00476 {
00477 int dist = abs((row) - mZoomRow);
00478 if (dist > 5) return mDefaultRowHeight;
00479 double div;
00480 if (dist == 0) div = 1.0;
00481 if (dist == 1) div = 0.45;
00482 if (dist == 2) div = 0.25;
00483 if (dist == 3) div = 0.15;
00484 if (dist == 4) div = 0.1;
00485 if (dist == 5) div = 0.05;
00486 return (int)(mDefaultRowZoomHeight*div+mDefaultRowHeight*(1.0-div));
00487 }
00488 return mDefaultRowHeight;
00489 }
00490
00491 int GetID(int row)
00492 {
00493 if (row >= 0 && row < mTotalRows && row < mSortSequence.size())
00494 return mSortSequence[row];
00495 else
00496 return -1;
00497 }
00498
00499 int GetRowForID(int id)
00500 {
00501 int size = mSortSequence.size();
00502 for (int i=0; i<mTotalRows && i<size; i++)
00503 if (mSortSequence[i] == id)
00504 return i;
00505 return -1;
00506 }
00507
00508 virtual String
00509 GetTextDataByID(String column, int row)
00510 {
00511 if (OutOfBounds(row))
00512 return "";
00513 std::ostringstream os;
00514 os << column << ":" << row;
00515 return os.str();
00516 }
00517
00518 virtual Array2dVec3UInt8*
00519 GetImageDataByID(String column, int row)
00520 {
00521 return 0;
00522 }
00523
00524 virtual Array2dVec3UInt8*
00525 GetVideoDataByID(String column, int row)
00526 {
00527 return 0;
00528 }
00529
00530 virtual double
00531 GetNormalizedDataByID(String column, int row)
00532 {
00533 return row / (double)mTotalRows;
00534 }
00535
00536 virtual int
00537 GetIntDataByID(String column, int row)
00538 {
00539 return 0;
00540 }
00541
00542 virtual double
00543 GetDoubleDataByID(String column, int row)
00544 {
00545 return 0;
00546 }
00547
00548 public:
00549
00550 void RemoveFilter(String column)
00551 {
00552 std::list<TableFilter*>::iterator it;
00553 for (it=mFilters.begin(); it!=mFilters.end(); it++)
00554 {
00555 if ((*it)->GetColumn() == column)
00556 mFilters.erase(it);
00557
00558 if (mFilters.size() == 0)
00559 mFiltersActive = false;
00560
00561
00562 if (!mFiltersWorking)
00563 ApplyFilters();
00564 break;
00565 }
00566 }
00567
00568 void RegisterFilter(TableFilter *t)
00569 {
00570 mFiltersWorking = true;
00571 RemoveFilter(t->GetColumn());
00572 mFiltersWorking = false;
00573 mFilters.push_back(t);
00574 mFiltersActive = true;
00575
00576 }
00577
00578 void EnableFilterByMark(int mark)
00579 {
00580 ILOG_DEBUG("Enable filter by mark for mark=" << mark);
00581 mFilterByMark = mark;
00582 ApplyFilters();
00583 }
00584
00585 int GetMarkFilter()
00586 {
00587 return mFilterByMark;
00588 }
00589
00590 int GetMarkFilterForEverything()
00591 {
00592 return 4|8|16|32|64|128;
00593 }
00594
00595 void DisableFilterByMark()
00596 {
00597 ILOG_DEBUG("Filter by mark disabled");
00598 mFilterByMark = -1;
00599 ApplyFilters();
00600 }
00601
00602 std::vector<TableSourceColumnDescription>
00603 GetColumns()
00604 {
00605 return mColumnNames;
00606 }
00607
00608 std::vector<TableSourceColumnDescription>
00609 GetExtraColumns()
00610 {
00611 return mExtraColumnNames;
00612 }
00613
00614 virtual void ApplyFilters()
00615 {
00616 SortAndFilter();
00617 }
00618
00619
00620 protected:
00621
00622 void AddStaticColumn(String name, int coltype, int width=120, int param=0)
00623 {
00624 TableSourceColumnDescription p(name, coltype, width, param);
00625 mColumnNames.push_back(p);
00626 }
00627
00628 void AddColumn(String name, int coltype, int width=120, int param=0)
00629 {
00630 TableSourceColumnDescription p(name, coltype, width, param);
00631 mExtraColumnNames.push_back(p);
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 if ((*it)->GetType() == TYPE_TEXT)
00658 {
00659 String txt = GetTextDataByID((*it)->GetColumn(), id);
00660 if ((*it)->IsFilteredByText(txt))
00661 return true;
00662 }
00663 if ((*it)->GetType() == TYPE_NORMALIZEDVALUE)
00664 {
00665 double dVal = GetNormalizedDataByID((*it)->GetColumn(),id);
00666 if ((*it)->IsFilteredByValue(dVal))
00667 return true;
00668 }
00669 if ((*it)->GetType() == TYPE_DOUBLE)
00670 {
00671 double dVal = GetDoubleDataByID((*it)->GetColumn(),id);
00672 if ((*it)->IsFilteredByValue(dVal))
00673 return true;
00674 }
00675 if ((*it)->GetType() == TYPE_INT)
00676 {
00677 int iVal = GetIntDataByID((*it)->GetColumn(),id);
00678
00679 if ((*it)->IsFilteredByValue(iVal))
00680 return true;
00681 }
00682 }
00683 return false;
00684 }
00685
00686 protected:
00687 int mTotalRows;
00688 int mFilteredRows;
00689
00690 int mDefaultRowHeight;
00691 int mDefaultRowZoomHeight;
00692 int mZoomRow;
00693
00694 private:
00695 bool mFiltersActive;
00696 bool mFiltersWorking;
00697 bool mSortAscending;
00698
00699 int mStartRow;
00700 int mDisplayRows;
00701 int mSortType;
00702 int mFilterByMark;
00703
00704 String mSortColumn;
00705
00706 std::vector<TableUpdateListener*> mTableListeners;
00707 std::list<TableFilter*> mFilters;
00708 std::vector<int> mSortSequence;
00709 std::map<int, int> mMarkedRows;
00710 std::map<int, bool> mVisibleRows;
00711
00712
00713 std::vector<TableSourceColumnDescription> mColumnNames;
00714 std::vector<TableSourceColumnDescription> mExtraColumnNames;
00715
00716 ILOG_VAR_DEC;
00717 };
00718
00719 ILOG_VAR_INIT(TableDataSource, Application.VideoExcel);
00720
00721 }
00722 }
00723 }
00724
00725 #endif // TableDataSource_h