NCBI C++ ToolKit
pager.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: pager.cpp 99053 2023-02-07 20:25:53Z ivanov $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Eugene Vasilchenko, Anton Golikov
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
31 #include <corelib/ncbistd.hpp>
32 #include <cgi/ncbicgi.hpp>
33 #include <html/pager.hpp>
34 
35 #include <stdio.h>
36 
38 
39 
40 const char* CPager::KParam_PageSize = "dispmax";
41 const char* CPager::KParam_ShownPageSize = "showndispmax";
42 const char* CPager::KParam_DisplayPage = "page";
43 const char* CPager::KParam_Page = "page ";
44 const char* CPager::KParam_PreviousPages = "previous pages";
45 const char* CPager::KParam_NextPages = "next pages";
46 const char* CPager::KParam_InputPage = "inputpage";
47 const char* CPager::KParam_NextPage = "Next Page";
48 const char* CPager::KParam_PrevPage = "Prev Page";
49 const char* CPager::KParam_GoToPage = "GoTo Page";
50 
51 CPager::CPager(const CCgiRequest& request,
52  int pageBlockSize,
53  int defaultPageSize,
54  EPagerView view /* = eImage */)
55  : m_PageSize(GetPageSize(request, defaultPageSize)),
56  m_PageBlockSize(max(1, pageBlockSize)),
57  m_PageChanged(false), m_view(view)
58 {
59  const TCgiEntries& entries = request.GetEntries();
60 
61  if ( IsPagerCommand(request) ) {
62  // look in preprocessed IMAGE values with empty string key
64  if (i != entries.end()) {
65  const string& value = i->second;
66  if (value == KParam_PreviousPages) {
67  // previous pages
68  // round to previous page block
69  m_PageChanged = true;
70  int page = GetDisplayedPage(request);
71  m_DisplayPage = page - page % m_PageBlockSize - 1;
72  }
73  else if (value == KParam_NextPages) {
74  // next pages
75  // round to next page block
76  m_PageChanged = true;
77  int page = GetDisplayedPage(request);
78  m_DisplayPage = page - page % m_PageBlockSize +
80  }
81  else if ( NStr::StartsWith(value, KParam_Page) ) {
82  // look for params like: "page 2"
83  string page = value.substr(strlen(KParam_Page));
84  try {
85  m_DisplayPage = NStr::StringToInt(page) - 1;
86  m_PageChanged = true;
87  } catch (exception& _DEBUG_ARG(e)) {
88  _TRACE( "Exception in CPager::CPager: " << e.what() );
89  m_PageChanged = false;
90  }
91  }
92  }
93  i = entries.find(KParam_InputPage);
94  if (i != entries.end()) {
95  try {
96  m_DisplayPage = NStr::StringToInt(string(i->second)) - 1;
98  m_PageChanged = true;
99  } catch (exception& _DEBUG_ARG(e)) {
100  _TRACE( "Exception in CPager::IsPagerCommand: " << e.what() );
101  m_PageChanged = false;
102  }
103  }
104  } else {
105  try {
106  m_PageChanged = true;
107  int page = GetDisplayedPage(request);
108  TCgiEntriesCI oldPageSize = entries.find(KParam_ShownPageSize);
109  if( !page || oldPageSize == entries.end() )
110  throw runtime_error("Error getting page params");
111  //number of the first element in old pagination
112  int oldFirstItem = page *
113  NStr::StringToInt(string(oldPageSize->second));
114  m_DisplayPage = oldFirstItem / m_PageSize;
115  } catch(exception& _DEBUG_ARG(e)) {
116  _TRACE( "Exception in CPager::CPager: " << e.what() );
117  m_DisplayPage = 0;
118  m_PageChanged = false;
119  }
120 
121  }
122  if( !m_PageChanged )
123  m_DisplayPage = GetDisplayedPage(request);
124 
126 }
127 
128 
130 {
131  TCgiEntries& entries = const_cast<TCgiEntries&>(request.GetEntries());
132 
133  // look in preprocessed IMAGE values with empty string key
135  if (i != entries.end()) {
136  const string& value = i->second.GetValue();
137  if (value == KParam_PreviousPages) {
138  // previous pages
139  return true;
140  }
141  else if (value == KParam_NextPages) {
142  // next pages
143  return true;
144  }
145  else if ( NStr::StartsWith(value, KParam_Page) ) {
146  // look for params like: "page 2"
147  string page = value.substr(strlen(KParam_Page));
148  try {
149  NStr::StringToInt(page);
150  return true;
151  } catch (exception& _DEBUG_ARG(e)) {
152  _TRACE( "Exception in CPager::IsPagerCommand: " << e.what() );
153  }
154  }
155  }
156  i = entries.find(KParam_InputPage);
157  if (i != entries.end()) {
158  try {
159  NStr::StringToInt(i->second.GetValue());
160  return true;
161  } catch (exception& _DEBUG_ARG(e)) {
162  _TRACE( "Exception in CPager::IsPagerCommand: " << e.what() );
163  }
164  }
165  return false;
166 }
167 
168 
170 {
171  const TCgiEntries& entries = request.GetEntries();
173 
174  if (entry != entries.end()) {
175  try {
176  int displayPage = NStr::StringToInt(string(entry->second));
177  if ( displayPage >= 0 )
178  return displayPage;
179  _TRACE( "Negative page start in CPager::GetDisplayedPage: " <<
180  displayPage );
181  } catch (exception& _DEBUG_ARG(e)) {
182  _TRACE( "Exception in CPager::GetDisplayedPage " << e.what() );
183  }
184  }
185  // use default page start
186  return 0;
187 }
188 
189 
190 int CPager::GetPageSize(const CCgiRequest& request, int defaultPageSize)
191 {
192  TCgiEntries& entries = const_cast<TCgiEntries&>(request.GetEntries());
193  TCgiEntriesCI entry;
194 
195  if( IsPagerCommand(request) ) {
196  entry = entries.find(KParam_ShownPageSize);
197  } else {
198  entry = entries.find(KParam_PageSize);
199  }
200  if (entry != entries.end()) {
201  try {
202  string dispMax = entry->second;
203  int pageSize = NStr::StringToInt(dispMax);
204  if( pageSize > 0 ) {
205  //replace dispmax for current page size
206  entries.erase(KParam_PageSize);
208  dispMax));
209  return pageSize;
210  }
211  _TRACE( "Nonpositive page size in CPager::GetPageSize: " <<
212  pageSize );
213  } catch (exception& _DEBUG_ARG(e)) {
214  _TRACE( "Exception in CPager::GetPageSize " << e.what() );
215  }
216  }
217  // use default page size
218  return defaultPageSize;
219 }
220 
221 
222 void CPager::SetItemCount(int itemCount)
223 {
224  m_ItemCount = itemCount;
225  if (m_DisplayPage * m_PageSize >= itemCount) {
226  m_DisplayPage = 0;
227  }
228 }
229 
230 
231 pair<int, int> CPager::GetRange(void) const
232 {
233  int firstItem = m_DisplayPage * m_PageSize;
234  return pair<int, int>(firstItem, min(firstItem + m_PageSize, m_ItemCount));
235 }
236 
237 
239 {
242 }
243 
244 
246 {
247  if (m_ItemCount <= m_PageSize) {
248  return 0;
249  }
250  int lastPage = (m_ItemCount - 1) / m_PageSize;
251  return new CHTMLPlainText(
252  "Page " + NStr::IntToString(m_DisplayPage + 1) +
253  " of " + NStr::IntToString(lastPage + 1));
254 }
255 
257 {
258  const int kBufSize = 1024;
259  char buf[kBufSize];
260  CHTML_div* node = new CHTML_div;
261  node->SetClass("medium2");
262 
263  if (m_ItemCount == 0) {
264  node->AppendChild(new CHTMLPlainText("0 items found"));
265  } else {
266  int firstItem = m_DisplayPage * m_PageSize + 1;
267  int endItem = min((m_DisplayPage + 1) * m_PageSize, m_ItemCount);
268  if (firstItem != endItem) {
269  snprintf(buf, kBufSize, "Items %d - %d", firstItem, endItem);
270  node->AppendChild(new CHTMLPlainText(buf));
271  } else {
272  snprintf(buf, kBufSize, "Item %d", firstItem);
273  node->AppendChild(new CHTMLPlainText(buf));
274  }
275  if( m_view != eTabs ) {
276  snprintf(buf, kBufSize, " of %d", m_ItemCount);
277  node->AppendChild(new CHTMLPlainText(buf));
278  }
279  }
280  return node;
281 }
282 
283 
284 CNCBINode* CPager::GetPagerView(const string& imgDir,
285  const int imgX, const int imgY,
286  const string& js_suffix /*kEmptyStr*/) const
287 {
288  if (m_ItemCount <= m_PageSize) {
289  return 0;
290  }
291  switch (m_view) {
292  case eButtons:
293  case eTabs:
294  return new CPagerViewButtons(*this, js_suffix);
295  case eJavaLess:
296  return new CPagerViewJavaLess(*this, js_suffix);
297  default:
298  break;
299  }
300  // Default old behavor
301  return new CPagerView(*this, imgDir, imgX, imgY);
302 }
303 
304 
305 CPagerView::CPagerView(const CPager& pager, const string& imgDir,
306  const int imgX, const int imgY)
307  : m_ImagesDir(imgDir), m_ImgSizeX(imgX), m_ImgSizeY(imgY), m_Pager(pager)
308 {
309  return;
310 }
311 
312 
314  const string& prefix, const string& suffix)
315 {
316  string s = NStr::IntToString(number + 1);
317  string name = CPager::KParam_Page + s;
318  CHTML_image* img;
319 
320  for ( size_t i = 0; i < s.size(); ++i ) {
321  img = new CHTML_image(name, m_ImagesDir + prefix + s[i] + suffix, 0);
322  img->SetAttribute("Alt", name);
323  if ( m_ImgSizeX )
324  img->SetWidth( m_ImgSizeX );
325  if ( m_ImgSizeY )
326  img->SetHeight( m_ImgSizeY );
327  node->AppendChild( img );
328  }
329 }
330 
331 
333  const string& prefix,
334  const string& suffix)
335 {
336  string s = NStr::IntToString(number + 1);
337  CHTML_img* img;
338 
339  for ( size_t i = 0; i < s.size(); ++i ) {
340  img = new CHTML_img(m_ImagesDir + prefix + s[i] + suffix);
341  img->SetAttribute("Alt", s);
342  if( m_ImgSizeX )
343  img->SetWidth( m_ImgSizeX );
344  if( m_ImgSizeY )
345  img->SetHeight( m_ImgSizeY );
346  node->AppendChild( img );
347  }
348 }
349 
350 
352 {
353  int column = 0;
354  int pageSize = m_Pager.m_PageSize;
355  int blockSize = m_Pager.m_PageBlockSize;
356 
357  int currentPage = m_Pager.m_DisplayPage;
358  int itemCount = m_Pager.m_ItemCount;
359 
360  int firstBlockPage = currentPage - currentPage % blockSize;
361  int lastPage = max(0, (itemCount + pageSize - 1) / pageSize - 1);
362  int lastBlockPage = min(firstBlockPage + blockSize - 1, lastPage);
363 
364  if (firstBlockPage > 0) {
366  m_ImagesDir + "prev.gif", 0);
368  if ( m_ImgSizeX )
369  img->SetWidth( m_ImgSizeX );
370  if ( m_ImgSizeY )
371  img->SetHeight( m_ImgSizeY );
372  InsertAt(0, column++, img);
373  }
374 
375  for (int i = firstBlockPage; i <= lastBlockPage ; ++i) {
376  if (i == currentPage) {
377  // current link
378  AddImageString(Cell(0, column++), i, "black_", ".gif");
379  }
380  else {
381  // normal link
382  AddImageString(Cell(0, column++), i, "", ".gif");
383  }
384  }
385 
386  if (lastPage != lastBlockPage) {
388  m_ImagesDir + "next.gif", 0);
390  if ( m_ImgSizeX )
391  img->SetWidth( m_ImgSizeX );
392  if ( m_ImgSizeY )
393  img->SetHeight( m_ImgSizeY );
394  InsertAt(0, column++, img);
395  }
396 }
397 
398 
399 CPagerViewButtons::CPagerViewButtons(const CPager& pager, const string& js_suffix)
400  : m_Pager(pager), m_jssuffix(js_suffix)
401 {
402 }
403 
405 {
406  int column = 0;
407  int pageSize = m_Pager.m_PageSize;
408  int currentPage = m_Pager.m_DisplayPage;
409  int itemCount = m_Pager.m_ItemCount;
410  int lastPage = max(0, (itemCount + pageSize - 1) / pageSize - 1);
411 
412  SetId("pager"+m_jssuffix);
413  if (currentPage > 0) {
414  CHTML_a* prev = new CHTML_a("javascript:var frm = " \
415  "document.frmQueryBox; " \
416  "frm.inputpage.value=" +
417  NStr::IntToString(currentPage) +
418  "; Go('Pager');", "Previous");
419  prev->SetClass("dblinks");
420  InsertAt(0, column, prev);
421  InsertAt(0, column++, new CHTML_nbsp);
422  }
423 
424  CHTML_input* butt = new CHTML_input("BUTTON", "GoToPage");
425  butt->SetClass("dblinks");
426  butt->SetAttribute("value", "Page");
428  "form.cmd.value='';form." +
429  string(CPager::KParam_InputPage) +
430  ".value=form.textpage" + m_jssuffix +
431  ".value;Go('Pager');");
432  InsertAt(0, column, butt);
433  InsertAt(0, column, new CHTML_nbsp);
434 
435  CHTML_input* textpage = new CHTML_text("textpage" + m_jssuffix, 4,
436  NStr::IntToString(currentPage + 1));
437  textpage->SetClass("dblinks");
438 
439  string suffix;
440  if ( m_jssuffix.empty() ) {
441  suffix = "1";
442  }
443 
445  "if(form.textpage" + suffix + "){form.textpage" +
446  suffix +".value=" + "this.value; "
447  "form." + CPager::KParam_InputPage +".value="
448  "this.value;}");
449 
451  "form." + string(CPager::KParam_InputPage) +".value="
452  "this.value;KeyPress('Pager',event);");
453 
454  InsertAt(0, column++, textpage);
455 
456  CHTML_div* div = new CHTML_div;
457  div->SetClass("medium2");
458  div->AppendChild(new CHTML_nbsp);
459  div->AppendChild(new CHTMLPlainText("of"));
460  div->AppendChild(new CHTML_nbsp);
461 
462  const int kBufSize = 1024;
463  char buf[kBufSize];
464  snprintf(buf, kBufSize, "%d", lastPage + 1);
465  div->AppendChild(new CHTMLPlainText(buf));
466  InsertAt(0, column++, div);
467 
468  // place holder for page num, to explicitly tell about new page num
471  if (currentPage < lastPage) {
472  CHTML_a* next = new CHTML_a("javascript:var frm = " \
473  "document.frmQueryBox;" \
474  "frm.inputpage.value=" +
475  NStr::IntToString(currentPage + 2) +
476  ";Go('Pager');", "Next");
477  next->SetClass("dblinks");
478  InsertAt(0, column, next);
479  InsertAt(0, column++, new CHTML_nbsp(2));
480  }
481 }
482 
483 
484 CPagerViewJavaLess::CPagerViewJavaLess(const CPager& pager, const string& js_suffix)
485  : m_Pager(pager), m_jssuffix(js_suffix)
486 {
487 }
488 
490 {
491  int item_count = m_Pager.m_ItemCount;
492  // container
493  this->SetCellPadding(0)->SetCellSpacing(0)->SetWidth("100%");
494 
495  if(item_count > 20) {
497  ->SetWidth("20%")->SetAlign("Right");
498 
499  this->InsertNextCell(
501  ->SetWidth("20%")->SetAlign("Right");
502 
504  ->SetWidth("20%")->SetAlign("Right");
505 
506  string page_no = "1";
507  if( m_Pager.m_DisplayPage * 20 < (item_count + 20)) {
509  }
510 
511  this->InsertNextCell((
514  ->SetWidth("20%")->SetAlign("Right");
515  }
516 }
517 
CCgiRequest::
Definition: ncbicgi.hpp:685
Definition: pager.hpp:54
Include a standard set of the NCBI C++ Toolkit most basic headers.
#define false
Definition: bool.h:36
static DLIST_TYPE *DLIST_NAME() prev(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:61
static DLIST_TYPE *DLIST_NAME() next(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:56
static const char * column
Definition: stats.c:23
TCgiEntries::iterator TCgiEntriesI
Definition: ncbicgi.hpp:639
TCgiEntries::const_iterator TCgiEntriesCI
Definition: ncbicgi.hpp:640
const TCgiEntries & GetEntries(void) const
Get a set of entries(decoded) received from the client.
Definition: ncbicgi.hpp:1181
#define _TRACE(message)
Definition: ncbidbg.hpp:122
#define _DEBUG_ARG(arg)
Definition: ncbidbg.hpp:134
CHTMLNode * SetId(const string &id)
void SetEventHandler(const EHTML_EH_Attribute event, const string &value)
Definition: html.cpp:152
CHTML_tc * Cell(TIndex row, TIndex column, ECellType type=eAnyCell)
Definition: html.cpp:1271
CHTMLNode * SetClass(const string &class_name)
CHTMLNode * SetWidth(int width)
CHTMLNode * SetAlign(const string &align)
CHTML_table * SetCellSpacing(int spacing)
CHTML_tc * InsertNextCell(CNCBINode *node)
CNCBINode * AppendChild(CNCBINode *child)
CHTML_tc * InsertAt(TIndex row, TIndex column, CNCBINode *node)
void SetAttribute(const string &name, const string &value)
CHTMLNode * SetHeight(int height)
CHTML_table * SetCellPadding(int padding)
@ eHTML_EH_Change
Definition: html.hpp:136
@ eHTML_EH_KeyPress
Definition: html.hpp:150
@ eHTML_EH_Click
Definition: html.hpp:137
void AddImageString(CNCBINode *node, int number, const string &imageStart, const string &imageEnd)
Definition: pager.cpp:313
friend class CPagerView
Definition: pager.hpp:147
int m_ImgSizeX
Definition: pager.hpp:165
static const char * KParam_Page
Definition: pager.hpp:120
static int GetDisplayedPage(const CCgiRequest &request)
Definition: pager.cpp:169
int m_DisplayPage
Definition: pager.hpp:136
int m_PageBlockSize
Definition: pager.hpp:132
static const char * KParam_ShownPageSize
Definition: pager.hpp:112
bool m_PageChanged
Definition: pager.hpp:142
const CPager & m_Pager
Definition: pager.hpp:168
static bool IsPagerCommand(const CCgiRequest &request)
Definition: pager.cpp:129
void AddInactiveImageString(CNCBINode *node, int number, const string &imageStart, const string &imageEnd)
Definition: pager.cpp:332
static const char * KParam_DisplayPage
Definition: pager.hpp:114
virtual void CreateSubNodes(void)
Definition: pager.cpp:404
static const char * KParam_PreviousPages
Definition: pager.hpp:116
string m_jssuffix
Definition: pager.hpp:188
static const char * KParam_NextPage
Definition: pager.hpp:124
string m_ImagesDir
Definition: pager.hpp:164
pair< int, int > GetRange(void) const
Definition: pager.cpp:231
CPagerViewButtons(const CPager &pager, const string &js_suffix)
Definition: pager.cpp:399
virtual void CreateSubNodes(void)
Definition: pager.cpp:238
static const char * KParam_PageSize
Definition: pager.hpp:110
int m_ItemCount
Definition: pager.hpp:139
const CPager & m_Pager
Definition: pager.hpp:187
static const char * KParam_GoToPage
Definition: pager.hpp:127
const CPager & m_Pager
Definition: pager.hpp:201
string m_jssuffix
Definition: pager.hpp:202
static const char * KParam_InputPage
Definition: pager.hpp:122
friend class CPagerViewJavaLess
Definition: pager.hpp:149
EPagerView m_view
Definition: pager.hpp:145
static const char * KParam_NextPages
Definition: pager.hpp:118
CPagerView(const CPager &pager, const string &imgDir, const int imgX, const int imgY)
Definition: pager.cpp:305
int m_PageBlockStart
Definition: pager.hpp:133
CPager(const CCgiRequest &request, int pageBlockSize=10, int defaultPageSize=10, EPagerView view=eImage)
Definition: pager.cpp:51
CNCBINode * GetPageInfo(void) const
Definition: pager.cpp:245
CNCBINode * GetPagerView(const string &imgDir, const int imgX=0, const int imgY=0, const string &js_suffix=kEmptyStr) const
Definition: pager.cpp:284
void SetItemCount(int count)
Definition: pager.cpp:222
static int GetPageSize(const CCgiRequest &request, int defaultPageSize=10)
Definition: pager.cpp:190
CPagerViewJavaLess(const CPager &pager, const string &js_suffix)
Definition: pager.cpp:484
int m_ImgSizeY
Definition: pager.hpp:166
virtual void CreateSubNodes(void)
Definition: pager.cpp:489
friend class CPagerViewButtons
Definition: pager.hpp:148
virtual void CreateSubNodes(void)
Definition: pager.cpp:351
EPagerView
Definition: pager.hpp:59
int m_PageSize
Definition: pager.hpp:131
CNCBINode * GetItemInfo(void) const
Definition: pager.cpp:256
static const char * KParam_PrevPage
Definition: pager.hpp:126
@ eButtons
Definition: pager.hpp:61
@ eJavaLess
Definition: pager.hpp:63
@ eTabs
Definition: pager.hpp:62
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
#define kEmptyStr
Definition: ncbistr.hpp:123
static int StringToInt(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to int.
Definition: ncbistr.cpp:630
static string IntToString(int value, TNumToStringFlags flags=0, int base=10)
Convert int to string.
Definition: ncbistr.hpp:5086
#define NcbiEmptyString
Definition: ncbistr.hpp:122
static bool StartsWith(const CTempString str, const CTempString start, ECase use_case=eCase)
Check if a string starts with a specified prefix value.
Definition: ncbistr.hpp:5414
char * buf
int i
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
T max(T x_, T y_)
T min(T x_, T y_)
static BOOL number
Definition: pcregrep.c:193
static const char * suffix[]
Definition: pcregrep.c:408
static const char * prefix[]
Definition: pcregrep.c:405
static const streamsize kBufSize
static wxAcceleratorEntry entries[3]
Modified on Mon Jul 15 05:33:44 2024 by modify_doxy.py rev. 669887