Wtx ~ Wt Extension Library
WtxLib
FieldDefLookupManager.cpp
1 /**************************************************************************
2 ###########################################################################
3 ##
4 ## $SHOWOFFDB_BEGIN_LICENSE$
5 ## Copyright (C) 2011 Lorimark Solutions, LLC and/or its subsidiary(-ies).
6 ## All rights reserved.
7 ## Contact: Lorimark Solutions, LLC (info@showoff-db.org)
8 ##
9 ## This file is part of the Showoff Database Application Framework.
10 ##
11 ## Commercial Usage
12 ## Licensees holding valid ShowoffDB Commercial licenses may use this file in
13 ## accordance with the ShowoffDB Commercial License Agreement provided with the
14 ## Software or, alternatively, in accordance with the terms contained in
15 ## a written agreement between you and Lorimark Solutions, LLC.
16 ##
17 ## GNU Lesser General Public License Usage
18 ## Alternatively, this file may be used under the terms of the GNU Lesser
19 ## General Public License version 2.1 as published by the Free Software
20 ## Foundation and appearing in the file LICENSE.LGPL included in the
21 ## packaging of this file. Please review the following information to
22 ## ensure the GNU Lesser General Public License version 2.1 requirements
23 ## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ##
25 ## In addition, as a special exception, Lorimark Solutions, LLC gives
26 ## you certain additional rights. These rights are described in the
27 ## Lorimark Solutions, LLC ShowoffDB LGPL Exception version 1.0, included in
28 ## the file LGPL_EXCEPTION.txt in this package.
29 ##
30 ## GNU General Public License Usage
31 ## Alternatively, this file may be used under the terms of the GNU
32 ## General Public License version 3.0 as published by the Free Software
33 ## Foundation and appearing in the file LICENSE.GPL included in the
34 ## packaging of this file. Please review the following information to
35 ## ensure the GNU General Public License version 3.0 requirements will be
36 ## met: http://www.gnu.org/copyleft/gpl.html.
37 ##
38 ## If you have questions regarding the use of this file, please contact
39 ## Lorimark Solutions, LLC at info@showoff-db.org.
40 ## $SHOWOFFDB_END_LICENSE$
41 ##
42 #############################################################################
43 ****************************************************************************/
44 
45 #include <Wt/WText.h>
46 #include <Wt/WDialog.h>
47 #include <Wt/WPushButton.h>
48 #include <Wt/WContainerWidget.h>
49 #include <Wt/WAbstractItemModel.h>
50 #include <Wt/WLineEdit.h>
51 //#include <Wt/WInPlaceEdit.h>
52 #include <Wt/WVBoxLayout.h>
53 #include <Wt/WTableView.h>
54 #include <Wt/WModelIndex.h>
55 
56 #include <Wtx/Core/Core.h>
57 #include <Wtx/Util/Util.h>
58 
59 #include "FieldDefLookupManager.h"
60 
61 #ifdef NEVER
62 Wt::Signal<> & Wtx::Dbo::FieldDefLookupManager::TableLineEdit::pickered()
63 {
64  return m_pickered;
65 }
66 #endif
67 
68 namespace {
69 
70 class TabLinEdi
71 : public Wt::WLineEdit
72 //: public Wt::WFormWidget
73 //: public Wtx::Dbo::FieldDefLookupManager::TableLineEdit
74 //: public Wt::WInPlaceEdit
75 {
76  public:
77 
78  TabLinEdi
79  (
80  int sid,
83  )
84  : m_session ( s ),
85  m_sourceID ( sid ),
86  m_fieldDef ( fieldDef )
87  {
88 
89  changed ().connect( this, &TabLinEdi::on_changed );
90  focussed ().connect( this, &TabLinEdi::on_focussed );
91  doubleClicked ().connect( this, &TabLinEdi::on_doubleClicked );
92 // lineEdit()-> changed() .connect( this, &TableLineEdit::on_changed );
93 // lineEdit()-> focussed() .connect( this, &TableLineEdit::on_focussed );
94 
95  } // endTabLinEdi()
96 
97  /*
98  ** this is kind of crummy. this is supposed to load
99  ** the model, but if an .id. value is specified then
100  ** its supposed to only load that id. but if no .id.
101  ** is specified (id==-1) then this is supposed to
102  ** load the _whole_ model. The idea being, it should
103  ** not load the model until it's absolutely necessary.
104  ** the concept is that we only need to load one item
105  ** out of the model if we're just loading the widget.
106  ** we only need 1 item to get the widget loaded, to
107  ** convert the id number in to a string-value. but
108  ** if the user never selects this control, then there's
109  ** no reason to load ALL the data, it just slows down
110  ** the user interface. this is my best attempt at
111  ** lazy-loading.
112  **
113  */
114  void loadModel( int id, const std::string & filter )
115  {
116  if( !m_loaded && fieldDef() && fieldDef()-> provider() /* m_fieldDef-> getLookupModel */ )
117  {
118 #ifdef NEVER
119  std::cout << __FILE__ << ":" << __LINE__
120  << " Loading Model id: " << id
121  << " sid:" << m_sourceID
122  << " tid:" << m_targetID
123  << std::endl
124  ;
125 #endif
126 
127  m_model = fieldDef()-> provider()-> model( m_sourceID, id, filter );
128 
129 // setModel( m_model );
130 // setModelColumn(1);
131 
132 // std::cout << __FILE__ << ":" << __LINE__ << " " << (void*)m_model.get() << std::endl;
133 // std::cout << __FILE__ << ":" << __LINE__ << " " << m_model-> rowCount() << std::endl;
134 
135  if( id == -1 )
136  m_loaded = true;
137  }
138  }
139 
140  void on_doubleClicked()
141  {
142  std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
143 
144  }
145 
146  void on_focussed()
147  {
148 #ifdef NEVER
149  std::cout << __FILE__ << ":" << __LINE__
150  << " " << m_sourceID
151  << " " << m_targetID
152  << " " << m_valueText
153  << " " << m_toolTip
154  << std::endl
155  ;
156 #endif
157 
158  loadModel( -1, "" );
159 
160 // for( int i=0; i< count(); i++ )
161 // if( itemText(i) == m_valueText )
162 // setCurrentIndex(i);
163 
164  setValueText( m_valueText );
165 
166  }
167 
168 // void on_textInput()
169 // {
170 // std::cout << __FILE__ << ":" << __LINE__ << " " << Wt::WLineEdit::valueText() << std::endl;
171 //
172 // if( !m_table )
173 // {
174 // }
175 // }
176 
177  /*
178  ** this fires when the widget looses focus and the value in it
179  ** is different than from when it started
180  **
181  */
182  void on_changed()
183  {
184  auto value = Wt::WLineEdit::valueText().toUTF8();
185 // auto value = lineEdit()-> valueText().toUTF8();
186 
187  /*
188  ** If the value is blank, then just zap the
189  ** values from the system, so that it doesn't
190  ** appear to be connected to anything.
191  **
192  */
193  if( value == "" )
194  {
195  m_targetID = -1;
196  m_valueText = "";
197  return;
198  }
199 
200  /*
201  ** If the provider has not been provided then
202  ** just quit.
203  **
204  */
205  if( !provider() )
206  {
207  std::cout << __FILE__ << ":" << __LINE__ << " no provider!" << std::endl;
208  return;
209  }
210 
211  m_targetID = provider()-> find_id( value );
212 
213  std::cout << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__ << "(): " << m_targetID << std::endl;
214 
215  if( m_targetID < 1 )
216  {
217  auto dialog = addChild( std::make_unique<Wt::WDialog>("item pickers") );
218  dialog-> rejectWhenEscapePressed(true);
219  dialog-> show();
220  auto cw = dialog-> contents()-> addNew<Wt::WContainerWidget>();
221  auto lw = std::make_unique<Wt::WVBoxLayout>();
222 
223  auto u_search = std::make_unique<Wt::WLineEdit>(value);
224  auto search = u_search.get();
225  search-> setDisabled(true);
226  lw-> addWidget( std::move( u_search ) );
227 
228  if( fieldDef()-> getTableView )
229  {
230 #ifdef NEVER
231  std::cout << __FILE__ << ":" << __LINE__
232  << " " << m_sourceID
233  << " " << m_targetID
234  << " " << search-> valueText().toUTF8()
235  << std::endl
236  ;
237 #endif
238 
239  auto u_table = fieldDef()-> getTableView( m_sourceID, m_targetID, search-> valueText().toUTF8(), m_session );
240  auto table = u_table.get();
241 
242  /*
243  ** make sure we actually ended up with a table-view
244  **
245  */
246  if( table )
247  {
248  table-> doubleClicked().connect( dialog, &Wt::WDialog::accept );
249  lw-> addWidget( std::move( u_table ), 1 );
250 
251  auto u_select = std::make_unique<Wt::WPushButton>("select");
252  u_select-> clicked().connect( dialog, &Wt::WDialog::accept );
253  lw-> addWidget( std::move( u_select ) );
254 
255  dialog-> finished().connect( [=]( Wt::DialogCode code )
256  {
257  /*
258  ** he must hit the 'select' button
259  **
260  */
261  if( dialog-> result() != Wt::DialogCode::Accepted )
262  return;
263 
264  /*
265  ** at most/least one row must be selected
266  **
267  */
268  if( table-> selectedIndexes().size() != 1 )
269  return;
270 
271  auto index = *table-> selectedIndexes().begin();
272 
273  m_targetID = Wt::asNumber( index.data() );
274 #ifdef NEVER
275  std::cout << __FILE__ << ":" << __LINE__
276  << " " << index.row()
277  << " " << index.column()
278  << " " << m_targetID
279  << std::endl
280  ;
281 #endif
282  setValueText( provider()-> get_string( m_targetID ) );
283 
284 // m_pickered.emit();
285 
286  }); // enddialog-> finished().connect( [=]( Wt::DialogCode code )
287 
288  }
289 
290  /*
291  ** even though we asked for a table-vew, we could not get one
292  ** so alert the user.
293  **
294  */
295  else
296  {
297  lw-> addWidget
298  (
299  std::make_unique<Wt::WText>
300  (
301  Wt::WString("FieldDefLookupTable.cpp:{1} 'getTableView' not returning view '{2}'")
302  .arg( __LINE__ )
303  .arg( m_field )
304  )
305  );
306 
307  }
308 
309  }
310 
311  else // if( !m_getTableView )
312  {
313  lw-> addWidget
314  (
315  std::make_unique<Wt::WText>
316  (
317  Wt::WString("FieldDefLookupTable.cpp:{1} 'getTableView' not set '{2}'")
318  .arg( __LINE__ )
319  .arg( m_field )
320  )
321  );
322  }
323 
324  auto u_cancel = std::make_unique<Wt::WPushButton>("cancel");
325  u_cancel-> clicked().connect( dialog, &Wt::WDialog::reject );
326  lw-> addWidget( std::move( u_cancel ) );
327 
328  cw-> setLayout( std::move(lw) );
329 
330  } // endif( m_targetID == -1 )
331 
332  else
333  {
334  std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
335 
336  setValueText( provider()-> get_string( m_targetID ) );
337  std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
338 
339  setToolTip( provider()-> get_toolTip( m_targetID ) );
340  }
341 
342 #ifdef NEVER
343  std::cout << __FILE__ << ":" << __LINE__
344  << "\n targetID: " << m_targetID
345  << "\n valueText: " << m_valueText
346  << std::endl
347  ;
348 #endif
349 
350 #ifdef NEVER
351  auto dialog = addChild( std::make_unique<Wt::WDialog>() );
352  dialog-> rejectWhenEscapePressed();
353  dialog-> contents()-> addNew<Wt::WText>("cannot put in false data");
354  dialog-> show();
355 #endif
356 
357 // std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
358 
359  } // endvoid on_changed()
360 
361 
362  Wt::WString valueText() const
363  {
364  auto retVal = Wt::WString("[null]");
365 
366  if( m_targetID != -1 )
367  retVal = Wt::WString("{1}: {2}]").arg( m_table ).arg( m_targetID );
368 
369 #ifdef NEVER
370  std::cout << __FILE__ << ":" << __LINE__ << "::" << __FUNCTION__ << "()"
371  << "\n m_loaded: " << m_loaded
372  << "\n m_field: " << m_field
373  << "\n m_table: " << m_table
374  << "\n m_sourceID: " << m_sourceID
375  << "\n m_targetID: " << m_targetID
376  << "\n retVal: " << retVal
377  << std::endl
378  ;
379 #endif
380 
381  return retVal;
382 
383  } // endWt::WString valueText() const
384 
385  void setValueText( const Wt::WString & value )
386  {
387  m_valueText = value.toUTF8();
388 
389 #ifdef NEVER
390  std::cout << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__
391  << " " << m_valueText
392  << std::endl
393  ;
394 #endif
395 
396  /*
397  ** if the value text is nothing, then wipe
398  ** it so that nothing shows.
399  **
400  */
401  if( m_valueText == "[null]" )
402  m_valueText = "";
403 
404  else
405  {
406  if( m_valueText.find(":") != std::string::npos )
407  {
408 #ifdef NEVER
409  std::cout << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__ << " " << m_valueText << std::endl;
410 #endif
411 
412  auto v = Wtx::Core::split( m_valueText, ':' );
413  m_table = v.at(0);
414  m_targetID = std::stoi(v.at(1));
415  loadModel( m_targetID, "" );
416 
417  if( fieldDef()-> provider() )
418  {
419  m_valueText = fieldDef()-> provider()-> get_string( m_targetID );
420  m_toolTip = fieldDef()-> provider()-> get_toolTip( m_targetID );
421  }
422 
423  } // endif( m_valueText.find(":") != std::string::npos )
424 
425  } // endif( m_valueText != "[null]" )
426 
427  Wt::WLineEdit::setValueText( m_valueText );
428  Wt::WLineEdit::setToolTip( m_toolTip );
429 // lineEdit()-> setValueText( m_valueText );
430 // lineEdit()-> setToolTip( m_toolTip );
431 
432 #ifdef NEVER
433  std::cout << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__
434  << "\n loaded: " << m_loaded
435  << "\n sourceID: " << m_sourceID
436  << "\n targetID: " << m_targetID
437  << "\n table: " << m_table
438  << "\n value: " << value
439  << "\n valueText:" << m_valueText
440  << "\n valueText:" << Wt::WLineEdit::valueText()
441 // << "\n valueText:" << lineEdit()-> valueText()
442  << "\n toolTip: " << m_toolTip
443  << std::endl
444  ;
445 #endif
446 
447  } // endvoid setValueText( const Wt::WString & value )
448 
449  Wtx::Dbo::FieldDefLookupManager * fieldDef() { return m_fieldDef; }
450  Wtx::Dbo::FieldDefLookupBase::Provider * provider() { return fieldDef()-> provider(); }
451 
452  Wtx::Dbo::FieldDefLookupManager * m_fieldDef = nullptr;
453  bool m_loaded = false;
454  std::string m_field;
455  std::string m_table;
456  int m_sourceID = -1;
457  int m_targetID = -1;
458  std::string m_valueText;
459  std::string m_toolTip;
460  Wtx::Dbo::Session & m_session;
461  std::shared_ptr<Wt::WAbstractItemModel> m_model = nullptr;
462 
463 }; // endclass TableLineEdit
464 
465 } // endnamespace {
466 
468 (
469  TableDef & td,
470  const char * fn,
471  int w,
472  int h,
473  Flags f,
474  std::string lb,
475  std::string ph,
476  std::string inf,
477  std::string tt,
478  int ht
479 )
480 : Wtx::Dbo::FieldDefLookupBase( td, fn, w, w, f, lb, ph, inf, tt, ht )
481 {
482 
483 }
484 
486 (
487  TableDef & td,
488  const char * fn,
489  std::string lb,
490  std::string ph,
491  std::string inf,
492  std::string tt,
493  int ht
494 )
495 : Wtx::Dbo::FieldDefLookupBase( td, fn, lb, ph, inf, tt, ht )
496 {
497 
498 }
499 
500 std::unique_ptr<Wt::WWidget> Wtx::Dbo::FieldDefLookupManager::createEditWidget( int sid, Wtx::Dbo::Session & session ) const
501 {
502 // std::cout << __FILE__ << ":" << __LINE__
503 // << "\n sid: " << sid
504 // << std::endl
505 // ;
506 
507 
508  if( !m_provider )
509  {
510  std::cout << __FILE__ << ":" << __LINE__ << " " << fieldName() << ": " << "Model provider not set" << std::endl;
511  }
512 
513 
514 // auto retVal = std::make_unique< TableLineEdit >( sid, getLookupModel, getTableView, session );
515  auto retVal = std::make_unique< TabLinEdi >( sid, const_cast<Wtx::Dbo::FieldDefLookupManager*>(this), session );
516  retVal-> m_table = "[" + targetTable;
517  retVal-> m_field = fieldName();
518 
519  return retVal;
520 
521 }
522 
523 
524 
Table Definition.
Definition: TableDef.h:72
Flags
Field Definition Flags.
Definition: FieldDefBase.h:101
FieldDefLookupManager(TableDef &td, const char *fn, int w=-1, int h=-1, Flags f=Flags::None, std::string lb="", std::string ph="", std::string inf="", std::string tt="", int ht=-1)
ctor