Wtx ~ Wt Extension Library
WtxLib
FieldDefLookupSuggest.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/WAbstractItemModel.h>
46 #include <Wt/WContainerWidget.h>
47 #include <Wt/WDialog.h>
48 #include <Wt/WLineEdit.h>
49 #include <Wt/WString.h>
50 #include <Wt/WSuggestionPopup.h>
51 #include <Wt/WText.h>
52 
53 #include <Wtx/Core/Core.h>
54 #include <Wtx/Util/Util.h>
55 
56 #include "FieldDefLookupSuggest.h"
57 
59 (
60  TableDef & td,
61  const char * fn,
62  int w,
63  int h,
64  Flags f,
65  std::string lb,
66  std::string ph,
67  std::string inf,
68  std::string tt,
69  int ht
70 )
71 : Wtx::Dbo::FieldDefLookupBase( td, fn, w, w, f, lb, ph, inf, tt, ht )
72 {
73 }
74 
75 
77 : public Wt::WSuggestionPopup
78 {
79  public:
80 
81  SmartSuggest( const Wt::WSuggestionPopup::Options & options )
82  : Wt::WSuggestionPopup( options )
83  {
84  }
85 
86 
87 }; // endclass SmartSuggest
88 
89 class SmartLineEdit
90 : public Wt::WLineEdit
91 {
92  public:
93 
94  void setEdit()
95  {
96 #ifdef NEVER
97  EventSignalBase& b = edit->keyPressed();
98 
99  connectObjJS(b, "editKeyDown");
100  connectObjJS(edit->keyWentDown(), "editKeyDown");
101  connectObjJS(edit->keyWentUp(), "editKeyUp");
102  connectObjJS(edit->blurred(), "delayHide");
103 
104  if (triggers.test(PopupTrigger::Editing))
105  edit->addStyleClass("Wt-suggest-onedit");
106 
107  if (triggers.test(PopupTrigger::DropDownIcon)) {
108  edit->addStyleClass("Wt-suggest-dropdown");
109  EventSignalBase& c = edit->clicked();
110  connectObjJS(c, "editClick");
111  connectObjJS(edit->mouseMoved(), "editMouseMove");
112  }
113 #endif
114 
115  }
116 
117 
118  SmartLineEdit( int sid, std::shared_ptr<Wt::WAbstractItemModel> (*getModel)(int sid,int tid,const std::string & filter,Wtx::Dbo::Session & session), Wtx::Dbo::Session & s )
119  : m_session(s),
120  m_sourceID(sid),
121  m_getModel(getModel)
122  {
123  changed().connect( this, &SmartLineEdit::on_changed );
124  textInput().connect( this, &SmartLineEdit::on_textInput );
125 
126  setAutoComplete( false );
127 
128  } // endSmartLineEdit( std::shared_ptr<Wt::WAbstractItemModel> model, Wtx::Dbo::Session & s )
129 
130  void setPopup()
131  {
132  std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
133 
134 // m_model = m_getModel( m_sourceID, m_targetID, "", m_session );
135 
136  if( !m_model )
137  return;
138 
139  if( m_popup )
140  return;
141 
142  if( m_model-> rowCount() < 100 )
143  {
144  std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
145 
146  Wt::WSuggestionPopup::Options options =
147  {
148  "<b>", // highlightBeginTag
149  "</b>", // highlightEndTag
150  0, // listSeparator (for multiple addresses)
151  " \\n", // whitespace
152  "-., \"@\\n;", // wordSeparators (within an address)
153  "" // appendReplacedText (prepare next email address)
154  };
155 
156  if( m_popup )
157  removeChild( m_popup );
158 
159  m_popup = addChild( std::make_unique<Wt::WSuggestionPopup>( options ) );
160  m_popup-> forEdit( this /*, Wt::PopupTrigger::DropDownIcon */ );
161 
162  m_popup-> setModel( m_model );
163  m_popup-> setModelColumn(1);
164 // popup-> setFilterLength(3);
165 
166  m_popup-> activated().connect( [=]( int index, Wt::WFormWidget * widget )
167  {
168  std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
169 
170  m_targetID = Wt::asNumber( m_model-> index( index, 0 ).data() );
171  m_valueText = Wt::asNumber( m_model-> index( index, 1 ).data() );
172 
173  });
174 
175  } // endif( m_model-> rowCount() < 100 )
176  }
177 
178  /*
179  ** this returns the ID value of the string
180  **
181  */
182  int get_id( const std::string & value )
183  {
184  std::cout << __FILE__ << ":" << __LINE__ << " " << value << std::endl;
185 
186  if( m_model )
187  {
188  std::cout << __FILE__ << ":" << __LINE__
189  << " " << m_model-> rowCount()
190  << std::endl
191  ;
192 
193  for( int i=0; i < m_model-> rowCount(); i++ )
194  {
195  auto id = Wt::asNumber(m_model-> index( i, 0 ).data());
196  auto ky = Wt::asString(m_model-> index( i, 1 ).data()).toUTF8();
197 
198  std::cout << __FILE__ << ":" << __LINE__ << " " << ky << std::endl;
199 
200  if( value == ky )
201  {
202  return id;
203  }
204 
205  }
206  }
207 
208  std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
209 
210  return -1;
211  }
212 
213  /*
214  ** this returns the string value of the ID
215  **
216  */
217  std::string get_string( int index )
218  {
219  std::cout << __FILE__ << ":" << __LINE__
220  << "\n field: " << m_field
221  << "\n index: " << index
222  << "\n model: " << (void*)m_model.get()
223  << std::endl;
224 
225  if( m_model && index > -1 )
226  {
227  for( int i=0; i < m_model-> rowCount(); i++ )
228  {
229  auto id = Wt::asNumber(m_model-> index( i, 0 ).data());
230  auto ky = Wt::asString(m_model-> index( i, 1 ).data()).toUTF8();
231 
232  if( index == id )
233  {
234  return ky;
235  }
236 
237  }
238 
239  }
240 
241  std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
242 
243  return "";
244  }
245 
246  /*
247  ** this fires when the widget looses focus and the value in it
248  ** is different than from when it started
249  **
250  */
251  void on_textInput()
252  {
253  auto value = Wt::WLineEdit::valueText().toUTF8();
254 
255  if( !m_model )
256  {
257  m_model = m_getModel( m_sourceID, -1, value, m_session );
258  setPopup();
259  }
260 
261  std::cout << __FILE__ << ":" << __LINE__
262  << "\n value:" << value
263  << "\n targetID:" << m_targetID
264  << "\n valueText:" << m_valueText
265  << "\n model rows:" << m_model-> rowCount()
266  << std::endl
267  ;
268 
269  }
270 
271  void on_changed()
272  {
273  std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
274 
275  auto value = Wt::WLineEdit::valueText().toUTF8();
276 
277  if( value == "" )
278  {
279  m_targetID = -1;
280  m_valueText = "";
281  if( m_popup )
282  {
283  removeChild( m_popup );
284  m_popup = nullptr;
285  }
286 
287  return;
288  }
289 
290  m_targetID = get_id( value );
291  m_valueText = value;
292 
293  std::cout << __FILE__ << ":" << __LINE__
294  << "\n targetID:" << m_targetID
295  << "\n valueText:" << m_valueText
296  << "\n model rows:" << m_model-> rowCount()
297  << std::endl
298  ;
299 
300 #ifdef NEVER
301  auto dialog = addChild( std::make_unique<Wt::WDialog>() );
302  dialog-> rejectWhenEscapePressed();
303  dialog-> contents()-> addNew<Wt::WText>("cannot put in false data");
304  dialog-> show();
305 #endif
306 
307  } // endvoid on_changed()
308 
309 
310  Wt::WString valueText() const
311  {
312  auto retVal = Wt::WString("[null]");
313 
314  if( m_targetID != -1 )
315  retVal = Wt::WString("{1}: {2}]").arg( m_table ).arg( m_targetID );
316 
317  std::cout << __FILE__ << ":" << __LINE__
318  << "\n field" << m_field
319  << "\n retVal" << retVal
320  << std::endl
321  ;
322 
323  return retVal;
324  }
325 
326  /*
327  ** this will set the value text
328  **
329  ** note that the value text comes in as a string, but the
330  ** string represents the item using the following format:
331  **
332  ** "[tableName: itemNumber]"
333  **
334  ** Therefore, the item can be located by referencing the
335  ** table name, and extracting the item number that is
336  ** following the colon.
337  **
338  **
339  */
340  void setValueText( const Wt::WString & value )
341  {
342  m_valueText = value.toUTF8();
343 
344  /*
345  ** if the value text is nothing, then wipe
346  ** it so that nothing shows.
347  **
348  */
349  if( m_valueText == "[null]" )
350  m_valueText = "";
351 
352  /*
353  ** the value text is something, so extract the
354  ** numeric from it and see if we can fetch the
355  ** _actual_ value text that should be in the
356  ** text editor.
357  **
358  */
359  else
360  {
361  if( m_valueText.find(":") != std::string::npos )
362  {
363  auto v = Wtx::Core::split( m_valueText, ':' );
364  m_table = v.at(0);
365  m_targetID = std::stoi(v.at(1));
366  m_model = m_getModel( m_sourceID, m_targetID, "", m_session );
367  m_valueText = get_string( m_targetID );
368  }
369  }
370 
371  /*
372  ** update the text edit field
373  **
374  */
375  Wt::WLineEdit::setValueText( m_valueText );
376 
377  } // endvoid setValueText( const Wt::WString & value )
378 
379  std::string m_field;
380  std::string m_table;
381  int m_sourceID = -1;
382  int m_targetID = -1;
383  std::string m_valueText;
384  Wtx::Dbo::Session & m_session;
385  std::shared_ptr<Wt::WAbstractItemModel> (*m_getModel)(int sid, int tid, const std::string & filter, Wtx::Dbo::Session & session) = nullptr;
386  std::shared_ptr<Wt::WAbstractItemModel> m_model = nullptr;
387  Wt::WSuggestionPopup * m_popup = nullptr;
388 
389 }; // endclass SmartLineEdit
390 
391 
392 std::unique_ptr<Wt::WWidget> Wtx::Dbo::FieldDefLookupSuggest::createEditWidget( int sid, Wtx::Dbo::Session & session ) const
393 {
394  auto retVal = std::make_unique<SmartLineEdit>( sid, getLookupModel, session );
395 
396  retVal-> m_field = fieldName();
397 
398  return retVal;
399 
400 } // endstd::unique_ptr<Wt::WWidget> Wtx::Dbo::FieldDefLookupSuggest::createEditWidget( int sid, Wtx::Dbo::Session & session ) const
401 
Table Definition.
Definition: TableDef.h:72
FieldDefLookupSuggest(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