Wtx ~ Wt Extension Library
WtxLib
FieldDefLookupWidget.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 "FieldDefLookupWidget.h"
60 
61 Wt::Signal<> & Wtx::Dbo::FieldDefLookupWidget::TableLineEdit::pickered()
62 {
63  return m_pickered;
64 }
65 
66 namespace {
67 
68 class TabLinEdi
70 //: public Wt::WInPlaceEdit
71 {
72  public:
73 
74  TabLinEdi
75  (
76  int sid,
79  )
80  : m_session ( s ),
81  m_sourceID ( sid ),
82  m_fieldDef ( fieldDef )
83  {
84 
85  changed() .connect( this, &TabLinEdi::on_changed );
86  focussed() .connect( this, &TabLinEdi::on_focussed );
87 // lineEdit()-> changed() .connect( this, &TableLineEdit::on_changed );
88 // lineEdit()-> focussed() .connect( this, &TableLineEdit::on_focussed );
89 
90  } // endTabLinEdi()
91 
92  /*
93  ** this is kind of crummy. this is supposed to load
94  ** the model, but if an .id. value is specified then
95  ** its supposed to only load that id. but if no .id.
96  ** is specified (id==-1) then this is supposed to
97  ** load the _whole_ model. The idea being, it should
98  ** not load the model until it's absolutely necessary.
99  ** the concept is that we only need to load one item
100  ** out of the model if we're just loading the widget.
101  ** we only need 1 item to get the widget loaded, to
102  ** convert the id number in to a string-value. but
103  ** if the user never selects this control, then there's
104  ** no reason to load ALL the data, it just slows down
105  ** the user interface. this is my best attempt at
106  ** lazy-loading.
107  **
108  */
109  void loadModel( int id, const std::string & filter )
110  {
111  if( !m_loaded && fieldDef() && fieldDef()-> provider() /* m_fieldDef-> getLookupModel */ )
112  {
113 #ifdef NEVER
114  std::cout << __FILE__ << ":" << __LINE__
115  << " Loading Model id: " << id
116  << " sid:" << m_sourceID
117  << " tid:" << m_targetID
118  << std::endl
119  ;
120 #endif
121 
122  m_model = fieldDef()-> provider()-> model( m_sourceID, id, filter );
123 
124 // setModel( m_model );
125 // setModelColumn(1);
126 
127 // std::cout << __FILE__ << ":" << __LINE__ << " " << (void*)m_model.get() << std::endl;
128 // std::cout << __FILE__ << ":" << __LINE__ << " " << m_model-> rowCount() << std::endl;
129 
130  if( id == -1 )
131  m_loaded = true;
132  }
133  }
134 
135  void on_focussed()
136  {
137 #ifdef NEVER
138  std::cout << __FILE__ << ":" << __LINE__
139  << " " << m_sourceID
140  << " " << m_targetID
141  << " " << m_valueText
142  << " " << m_toolTip
143  << std::endl
144  ;
145 #endif
146 
147  loadModel( -1, "" );
148 
149 // for( int i=0; i< count(); i++ )
150 // if( itemText(i) == m_valueText )
151 // setCurrentIndex(i);
152 
153  setValueText( m_valueText );
154 
155  }
156 
157 // void on_textInput()
158 // {
159 // std::cout << __FILE__ << ":" << __LINE__ << " " << Wt::WLineEdit::valueText() << std::endl;
160 //
161 // if( !m_table )
162 // {
163 // }
164 // }
165 
166  /*
167  ** this fires when the widget looses focus and the value in it
168  ** is different than from when it started
169  **
170  */
171  void on_changed()
172  {
173  auto value = Wt::WLineEdit::valueText().toUTF8();
174 // auto value = lineEdit()-> valueText().toUTF8();
175 
176  /*
177  ** If the value is blank, then just zap the
178  ** values from the system, so that it doesn't
179  ** appear to be connected to anything.
180  **
181  */
182  if( value == "" )
183  {
184  m_targetID = -1;
185  m_valueText = "";
186  return;
187  }
188 
189  /*
190  ** If the provider has not been provided then
191  ** just quit.
192  **
193  */
194  if( !provider() )
195  {
196  std::cout << __FILE__ << ":" << __LINE__ << " no provider!" << std::endl;
197  return;
198  }
199 
200  m_targetID = provider()-> find_id( value );
201 
202  if( m_targetID < 1 )
203  {
204  auto dialog = addChild( std::make_unique<Wt::WDialog>("item pickers") );
205  dialog-> rejectWhenEscapePressed(true);
206  dialog-> show();
207  auto cw = dialog-> contents()-> addNew<Wt::WContainerWidget>();
208  auto lw = std::make_unique<Wt::WVBoxLayout>();
209 
210  auto u_search = std::make_unique<Wt::WLineEdit>(value);
211  auto search = u_search.get();
212  search-> setDisabled(true);
213  lw-> addWidget( std::move( u_search ) );
214 
215  if( fieldDef()-> getTableView )
216  {
217 #ifdef NEVER
218  std::cout << __FILE__ << ":" << __LINE__
219  << " " << m_sourceID
220  << " " << m_targetID
221  << " " << search-> valueText().toUTF8()
222  << std::endl
223  ;
224 #endif
225 
226  auto u_table = fieldDef()-> getTableView( m_sourceID, m_targetID, search-> valueText().toUTF8(), m_session );
227  auto table = u_table.get();
228 
229  /*
230  ** make sure we actually ended up with a table-view
231  **
232  */
233  if( table )
234  {
235  table-> doubleClicked().connect( dialog, &Wt::WDialog::accept );
236  lw-> addWidget( std::move( u_table ), 1 );
237 
238  auto u_select = std::make_unique<Wt::WPushButton>("select");
239  u_select-> clicked().connect( dialog, &Wt::WDialog::accept );
240  lw-> addWidget( std::move( u_select ) );
241 
242  dialog-> finished().connect( [=]( Wt::DialogCode code )
243  {
244  /*
245  ** he must hit the 'select' button
246  **
247  */
248  if( dialog-> result() != Wt::DialogCode::Accepted )
249  return;
250 
251  /*
252  ** at most/least one row must be selected
253  **
254  */
255  if( table-> selectedIndexes().size() != 1 )
256  return;
257 
258  auto index = *table-> selectedIndexes().begin();
259 
260  m_targetID = Wt::asNumber( index.data() );
261 #ifdef NEVER
262  std::cout << __FILE__ << ":" << __LINE__
263  << " " << index.row()
264  << " " << index.column()
265  << " " << m_targetID
266  << std::endl
267  ;
268 #endif
269  setValueText( provider()-> get_string( m_targetID ) );
270 
271  m_pickered.emit();
272  Wt::WFormWidget::blurred().emit();
273 
274  }); // enddialog-> finished().connect( [=]( Wt::DialogCode code )
275 
276  }
277 
278  /*
279  ** even though we asked for a table-vew, we could not get one
280  ** so alert the user.
281  **
282  */
283  else
284  {
285  lw-> addWidget
286  (
287  std::make_unique<Wt::WText>
288  (
289  Wt::WString("FieldDefLookupTable.cpp:{1} 'getTableView' not returning view '{2}'")
290  .arg( __LINE__ )
291  .arg( m_field )
292  )
293  );
294 
295  }
296 
297  }
298 
299  else // if( !m_getTableView )
300  {
301  lw-> addWidget
302  (
303  std::make_unique<Wt::WText>
304  (
305  Wt::WString("FieldDefLookupTable.cpp:{1} 'getTableView' not set '{2}'")
306  .arg( __LINE__ )
307  .arg( m_field )
308  )
309  );
310  }
311 
312  auto u_cancel = std::make_unique<Wt::WPushButton>("cancel");
313  u_cancel-> clicked().connect( dialog, &Wt::WDialog::reject );
314  lw-> addWidget( std::move( u_cancel ) );
315 
316  cw-> setLayout( std::move(lw) );
317 
318  } // endif( m_targetID == -1 )
319 
320  else
321  {
322  std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
323 
324  setValueText( provider()-> get_string( m_targetID ) );
325  std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
326 
327  setToolTip( provider()-> get_toolTip( m_targetID ) );
328  }
329 
330 #ifdef NEVER
331  std::cout << __FILE__ << ":" << __LINE__
332  << "\n targetID: " << m_targetID
333  << "\n valueText: " << m_valueText
334  << std::endl
335  ;
336 #endif
337 
338 #ifdef NEVER
339  auto dialog = addChild( std::make_unique<Wt::WDialog>() );
340  dialog-> rejectWhenEscapePressed();
341  dialog-> contents()-> addNew<Wt::WText>("cannot put in false data");
342  dialog-> show();
343 #endif
344 
345 // std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
346 
347  } // endvoid on_changed()
348 
349 
350  Wt::WString valueText() const
351  {
352  auto retVal = Wt::WString("[null]");
353 
354  if( m_targetID != -1 )
355  retVal = Wt::WString("{1}: {2}]").arg( m_table ).arg( m_targetID );
356 
357 #ifdef NEVER
358  std::cout << __FILE__ << ":" << __LINE__ << "::" << __FUNCTION__ << "()"
359  << "\n m_loaded: " << m_loaded
360  << "\n m_field: " << m_field
361  << "\n m_table: " << m_table
362  << "\n m_sourceID: " << m_sourceID
363  << "\n m_targetID: " << m_targetID
364  << "\n retVal: " << retVal
365  << std::endl
366  ;
367 #endif
368 
369  return retVal;
370 
371  } // endWt::WString valueText() const
372 
373  void setValueText( const Wt::WString & value )
374  {
375  m_valueText = value.toUTF8();
376 
377 #ifdef NEVER
378  std::cout << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__
379  << " " << m_valueText
380  << std::endl
381  ;
382 #endif
383 
384  /*
385  ** if the value text is nothing, then wipe
386  ** it so that nothing shows.
387  **
388  */
389  if( m_valueText == "[null]" )
390  m_valueText = "";
391 
392  else
393  {
394  if( m_valueText.find(":") != std::string::npos )
395  {
396 #ifdef NEVER
397  std::cout << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__ << " " << m_valueText << std::endl;
398 #endif
399 
400  auto v = Wtx::Core::split( m_valueText, ':' );
401  m_table = v.at(0);
402  m_targetID = std::stoi(v.at(1));
403  loadModel( m_targetID, "" );
404 
405  if( fieldDef()-> provider() )
406  {
407  m_valueText = fieldDef()-> provider()-> get_string( m_targetID );
408  m_toolTip = fieldDef()-> provider()-> get_toolTip( m_targetID );
409  }
410 
411  } // endif( m_valueText.find(":") != std::string::npos )
412 
413  } // endif( m_valueText != "[null]" )
414 
415  Wt::WLineEdit::setValueText( m_valueText );
416  Wt::WLineEdit::setToolTip( m_toolTip );
417 // lineEdit()-> setValueText( m_valueText );
418 // lineEdit()-> setToolTip( m_toolTip );
419 
420 #ifdef NEVER
421  std::cout << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__
422  << "\n loaded: " << m_loaded
423  << "\n sourceID: " << m_sourceID
424  << "\n targetID: " << m_targetID
425  << "\n table: " << m_table
426  << "\n value: " << value
427  << "\n valueText:" << m_valueText
428  << "\n valueText:" << Wt::WLineEdit::valueText()
429 // << "\n valueText:" << lineEdit()-> valueText()
430  << "\n toolTip: " << m_toolTip
431  << std::endl
432  ;
433 #endif
434 
435  } // endvoid setValueText( const Wt::WString & value )
436 
437  Wtx::Dbo::FieldDefLookupWidget * fieldDef() { return m_fieldDef; }
438  Wtx::Dbo::FieldDefLookupBase::Provider * provider() { return fieldDef()-> provider(); }
439 
440  Wtx::Dbo::FieldDefLookupWidget * m_fieldDef = nullptr;
441  bool m_loaded = false;
442  std::string m_field;
443  std::string m_table;
444  int m_sourceID = -1;
445  int m_targetID = -1;
446  std::string m_valueText;
447  std::string m_toolTip;
448  Wtx::Dbo::Session & m_session;
449  std::shared_ptr<Wt::WAbstractItemModel> m_model = nullptr;
450 
451 }; // endclass TableLineEdit
452 
453 } // endnamespace {
454 
456 (
457  TableDef & td,
458  const char * fn,
459  int w,
460  int h,
461  Flags f,
462  std::string lb,
463  std::string ph,
464  std::string inf,
465  std::string tt,
466  int ht
467 )
468 : Wtx::Dbo::FieldDefLookupBase( td, fn, w, w, f, lb, ph, inf, tt, ht )
469 {
470 
471 }
472 
474 (
475  TableDef & td,
476  const char * fn,
477  std::string lb,
478  std::string ph,
479  std::string inf,
480  std::string tt,
481  int ht
482 )
483 : Wtx::Dbo::FieldDefLookupBase( td, fn, lb, ph, inf, tt, ht )
484 {
485 
486 }
487 
488 std::unique_ptr<Wt::WWidget> Wtx::Dbo::FieldDefLookupWidget::createEditWidget( int sid, Wtx::Dbo::Session & session ) const
489 {
490 // std::cout << __FILE__ << ":" << __LINE__
491 // << "\n sid: " << sid
492 // << std::endl
493 // ;
494 
495 
496  if( !m_provider )
497  {
498  std::cout << __FILE__ << ":" << __LINE__ << " " << fieldName() << ": " << "Model provider not set" << std::endl;
499  }
500 
501 
502 // auto retVal = std::make_unique< TableLineEdit >( sid, getLookupModel, getTableView, session );
503  auto retVal = std::make_unique< TabLinEdi >( sid, const_cast<Wtx::Dbo::FieldDefLookupWidget*>(this), session );
504  retVal-> m_table = "[" + targetTable;
505  retVal-> m_field = fieldName();
506 
507  return retVal;
508 
509 }
510 
511 
512 
Table Definition.
Definition: TableDef.h:72
FieldDefLookupWidget(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
Flags
Field Definition Flags.
Definition: FieldDefBase.h:101