MythTV  master
videoselector.cpp
Go to the documentation of this file.
1 // c
2 #include <chrono>
3 #include <cstdlib>
4 #include <unistd.h>
5 
6 // qt
7 #include <QDir>
8 #include <QTimer>
9 
10 // mythtv
11 #include <mythcontext.h>
12 #include <mythdb.h>
13 #include <mythuitext.h>
14 #include <mythuibutton.h>
15 #include <mythuiimage.h>
16 #include <mythuibuttonlist.h>
17 #include <mythmainwindow.h>
18 #include <mythdialogbox.h>
19 #include <metadata/videoutils.h>
20 #include <remotefile.h>
21 
22 // mytharchive
23 #include "archiveutil.h"
24 #include "videoselector.h"
25 
26 VideoSelector::VideoSelector(MythScreenStack *parent, QList<ArchiveItem *> *archiveList)
27  :MythScreenType(parent, "VideoSelector"),
28  m_archiveList(archiveList)
29 {
33 }
34 
36 {
37  delete m_videoList;
38  while (!m_selectedList.isEmpty())
39  delete m_selectedList.takeFirst();
40  m_selectedList.clear();
42 }
43 
45 {
46  // Load the theme for this screen
47  bool foundtheme = LoadWindowFromXML("mytharchive-ui.xml", "video_selector", this);
48  if (!foundtheme)
49  return false;
50 
51  bool err = false;
52  UIUtilE::Assign(this, m_okButton, "ok_button", &err);
53  UIUtilE::Assign(this, m_cancelButton, "cancel_button", &err);
54  UIUtilE::Assign(this, m_categorySelector, "category_selector", &err);
55  UIUtilE::Assign(this, m_videoButtonList, "videolist", &err);
56  UIUtilE::Assign(this, m_titleText, "videotitle", &err);
57  UIUtilE::Assign(this, m_plotText, "videoplot", &err);
58  UIUtilE::Assign(this, m_filesizeText, "filesize", &err);
59  UIUtilE::Assign(this, m_coverImage, "cover_image", &err);
60  UIUtilE::Assign(this, m_warningText, "warning_text", &err);
61  UIUtilE::Assign(this, m_plText, "parentallevel_text", &err);
62 
63  if (err)
64  {
65  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'video_selector'");
66  return false;
67  }
68 
71 
74 
75  getVideoList();
80 
82 
84 
86 
89 
90  return true;
91 }
92 
93 bool VideoSelector::keyPressEvent(QKeyEvent *event)
94 {
95  if (GetFocusWidget()->keyPressEvent(event))
96  return true;
97 
98  QStringList actions;
99  bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
100 
101  for (int i = 0; i < actions.size() && !handled; i++)
102  {
103  QString action = actions[i];
104  handled = true;
105 
106  if (action == "MENU")
107  {
108  ShowMenu();
109  }
110  else if (action == "1")
111  {
113  }
114  else if (action == "2")
115  {
117  }
118  else if (action == "3")
119  {
121  }
122  else if (action == "4")
123  {
125  }
126  else
127  handled = false;
128  }
129 
130  if (!handled && MythScreenType::keyPressEvent(event))
131  handled = true;
132 
133  return handled;
134 }
135 
137 {
138  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
139 
140  auto *menuPopup = new MythDialogBox(tr("Menu"), popupStack, "actionmenu");
141 
142  if (menuPopup->Create())
143  popupStack->AddScreen(menuPopup);
144 
145  menuPopup->SetReturnEvent(this, "action");
146 
147  menuPopup->AddButton(tr("Clear All"), &VideoSelector::clearAll);
148  menuPopup->AddButton(tr("Select All"), &VideoSelector::selectAll);
149 }
150 
152 {
153  while (!m_selectedList.isEmpty())
154  m_selectedList.takeFirst();
155  m_selectedList.clear();
156 
157  for (auto *v : *m_videoList)
158  m_selectedList.append(v);
159 
160  updateVideoList();
161 }
162 
164 {
165  while (!m_selectedList.isEmpty())
166  m_selectedList.takeFirst();
167  m_selectedList.clear();
168 
169  updateVideoList();
170 }
171 
173 {
175  {
176  int index = m_selectedList.indexOf(item->GetData().value<VideoInfo *>());
177  if (index != -1)
178  m_selectedList.takeAt(index);
180  }
181  else
182  {
183  int index = m_selectedList.indexOf(item->GetData().value<VideoInfo *>());
184  if (index == -1)
185  m_selectedList.append(item->GetData().value<VideoInfo *>());
186 
188  }
189 }
190 
192 {
193  auto *v = item->GetData().value<VideoInfo *>();
194 
195  if (!v)
196  return;
197 
198  if (m_titleText)
199  m_titleText->SetText(v->title);
200 
201  if (m_plotText)
202  m_plotText->SetText(v->plot);
203 
204  if (m_coverImage)
205  {
206  if (v->coverfile != "" && v->coverfile != "No Cover")
207  {
208  m_coverImage->SetFilename(v->coverfile);
209  m_coverImage->Load();
210  }
211  else
212  {
213  m_coverImage->SetFilename("blank.png");
214  m_coverImage->Load();
215  }
216  }
217 
218  if (m_filesizeText)
219  {
220  if (v->size == 0)
221  {
222  struct stat fileinfo {};
223 
224  bool bExists = RemoteFile::Exists(v->filename, &fileinfo);
225  if (bExists)
226  v->size = (uint64_t)fileinfo.st_size;
227 
228  if (!bExists)
229  {
230  LOG(VB_GENERAL, LOG_ERR,
231  QString("VideoSelector: Cannot find file: %1")
232  .arg(v->filename));
233  }
234  }
235 
236  m_filesizeText->SetText(formatSize(v->size / 1024));
237  }
238 }
239 
241 {
242  // loop though selected videos and add them to the list
243  // remove any items that have been removed from the list
244  QList<ArchiveItem *> tempAList;
245  for (auto *a : qAsConst(*m_archiveList))
246  {
247  bool found = false;
248 
249  for (const auto *v : qAsConst(m_selectedList))
250  {
251  if (a->type != "Video" || a->filename == v->filename)
252  {
253  found = true;
254  break;
255  }
256  }
257 
258  if (!found)
259  tempAList.append(a);
260  }
261 
262  for (auto *x : qAsConst(tempAList))
263  m_archiveList->removeAll(x);
264 
265  // remove any items that are already in the list
266  QList<VideoInfo *> tempSList;
267  for (auto *v : qAsConst(m_selectedList))
268  {
269  for (const auto *a : qAsConst(*m_archiveList))
270  {
271  if (a->filename == v->filename)
272  {
273  tempSList.append(v);
274  break;
275  }
276  }
277  }
278 
279  for (auto *x : qAsConst(tempSList))
280  m_selectedList.removeAll(x);
281 
282  // add all that are left
283  for (const auto *v : qAsConst(m_selectedList))
284  {
285  auto *a = new ArchiveItem;
286  a->type = "Video";
287  a->title = v->title;
288  a->subtitle = "";
289  a->description = v->plot;
290  a->startDate = "";
291  a->startTime = "";
292  a->size = v->size;
293  a->newsize = v->size;
294  a->filename = v->filename;
295  a->hasCutlist = false;
296  a->useCutlist = false;
297  a->duration = 0;
298  a->cutDuration = 0;
299  a->videoWidth = 0;
300  a->videoHeight = 0;
301  a->fileCodec = "";
302  a->videoCodec = "";
303  a->encoderProfile = nullptr;
304  a->editedDetails = false;
305  m_archiveList->append(a);
306  }
307 
308  emit haveResult(true);
309  Close();
310 }
311 
313 {
314  emit haveResult(false);
315  Close();
316 }
317 
319 {
320  if (!m_videoList)
321  return;
322 
324 
325  if (m_categorySelector)
326  {
327  for (auto *v : *m_videoList)
328  {
329  if (v->category == m_categorySelector->GetValue() ||
330  m_categorySelector->GetValue() == tr("All Videos"))
331  {
332  if (v->parentalLevel <= m_currentParentalLevel)
333  {
334  auto* item = new MythUIButtonListItem(m_videoButtonList,
335  v->title);
336  item->setCheckable(true);
337  if (m_selectedList.indexOf(v) != -1)
338  {
339  item->setChecked(MythUIButtonListItem::FullChecked);
340  }
341  else
342  {
343  item->setChecked(MythUIButtonListItem::NotChecked);
344  }
345 
346  item->SetData(QVariant::fromValue(v));
347  }
348  }
349  }
350  }
351 
352  if (m_videoButtonList->GetCount() > 0)
353  {
356  m_warningText->Hide();
357  }
358  else
359  {
360  m_warningText->Show();
361  m_titleText->Reset();
362  m_plotText->Reset();
363  m_coverImage->SetFilename("blank.png");
364  m_coverImage->Load();
366  }
367 }
368 
369 std::vector<VideoInfo *> *VideoSelector::getVideoListFromDB(void)
370 {
371  // get a list of category's
372  using CategoryMap = QMap<int, QString>;
373  CategoryMap categoryMap;
374  MSqlQuery query(MSqlQuery::InitCon());
375  query.prepare("SELECT intid, category FROM videocategory");
376 
377  if (query.exec())
378  {
379  while (query.next())
380  {
381  int id = query.value(0).toInt();
382  QString category = query.value(1).toString();
383  categoryMap.insert(id, category);
384  }
385  }
386 
387  query.prepare("SELECT intid, title, plot, length, filename, coverfile, "
388  "category, showlevel, subtitle, season, episode, host "
389  "FROM videometadata ORDER BY title,season,episode");
390 
391  if (query.exec() && query.size())
392  {
393  auto *videoList = new std::vector<VideoInfo*>;
394  QString episode;
395  while (query.next())
396  {
397  // Exclude iso images as they aren't supported
398  QString filename = query.value(4).toString();
399  if (filename.endsWith(".iso") || filename.endsWith(".ISO"))
400  continue;
401 
402  auto *info = new VideoInfo;
403 
404  info->id = query.value(0).toInt();
405  if (query.value(9).toInt() > 0)
406  {
407  episode = query.value(10).toString();
408  if (episode.size() < 2)
409  episode.prepend("0");
410  info->title = QString("%1 %2x%3 - %4")
411  .arg(query.value(1).toString(),
412  query.value(9).toString(),
413  episode,
414  query.value(8).toString());
415  }
416  else
417  info->title = query.value(1).toString();
418 
419  info->plot = query.value(2).toString();
420  info->size = 0; //query.value(3).toInt();
421  QString host = query.value(11).toString();
422 
423  // try to find the file locally
424  if (host.isEmpty())
425  {
426  // must already be a local filename?
427  info->filename = filename;
428  }
429  else
430  {
431  // if the file is on this host then we should be able to find it locally
432  if (host == gCoreContext->GetHostName())
433  {
434  StorageGroup videoGroup("Videos", gCoreContext->GetHostName(), false);
435  info->filename = videoGroup.FindFile(filename);
436 
437  // sanity check the file exists
438  if (!QFile::exists(info->filename))
439  {
440  LOG(VB_GENERAL, LOG_ERR,
441  QString("VideoSelector: Failed to find local file '%1'").arg(info->filename));
442  info->filename.clear();
443  }
444  }
445 
446  if (info->filename.isEmpty())
447  {
448  // file must not be local or doesn't exist
449  info->filename = generate_file_url("Videos", host, filename);
450  }
451  }
452 
453  LOG(VB_FILE, LOG_INFO,
454  QString("VideoSelector: found file '%1'").arg(info->filename));
455 
456  info->coverfile = query.value(5).toString();
457  info->category = categoryMap[query.value(6).toInt()];
458  info->parentalLevel = query.value(7).toInt();
459  if (info->category.isEmpty())
460  info->category = "(None)";
461  videoList->push_back(info);
462  }
463 
464  return videoList;
465  }
466 
467  LOG(VB_GENERAL, LOG_ERR, "VideoSelector: Failed to get any videos");
468 
469  return nullptr;
470 }
471 
473 {
475  QStringList categories;
476 
477  if (m_videoList && !m_videoList->empty())
478  {
479  for (auto *v : *m_videoList)
480  {
481  if (categories.indexOf(v->category) == -1)
482  categories.append(v->category);
483  }
484  }
485  else
486  {
487  QTimer::singleShot(100ms, this, &VideoSelector::cancelPressed);
488  return;
489  }
490 
491  // sort and add categories to selector
492  categories.sort();
493 
494  if (m_categorySelector)
495  {
496  new MythUIButtonListItem(m_categorySelector, tr("All Videos"));
498 
499  for (int x = 0; x < categories.count(); x++)
500  {
501  new MythUIButtonListItem(m_categorySelector, categories[x]);
502  }
503  }
504 
505  setCategory(nullptr);
506 }
507 
509 {
510  (void)item;
511  updateVideoList();
512 }
513 
515 {
516  if (!m_videoList)
517  return;
518 
519  m_selectedList.clear();
520 
521  for (const auto *a : qAsConst(*m_archiveList))
522  {
523  for (auto *v : qAsConst(*m_videoList))
524  {
525  if (v->filename == a->filename)
526  {
527  if (m_selectedList.indexOf(v) == -1)
528  m_selectedList.append(v);
529  break;
530  }
531  }
532  }
533 }
534 
536 {
538 }
539 
541 {
542  if (passwordValid)
543  {
544  m_currentParentalLevel = newLevel;
545  updateVideoList();
546  m_plText->SetText(QString::number(newLevel));
547  }
548  else
549  ShowOkPopup(tr("You need to enter a valid password for this parental level"));
550 }
551 
MythUIButton::Clicked
void Clicked()
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:806
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
generate_file_url
QString generate_file_url(const QString &storage_group, const QString &host, const QString &path)
Definition: videoutils.h:65
formatSize
static QString formatSize(int64_t size, int prec)
Definition: recordingutils.cpp:22
VideoSelector::clearAll
void clearAll(void)
Definition: videoselector.cpp:163
VideoSelector::setCategory
void setCategory(MythUIButtonListItem *item)
Definition: videoselector.cpp:508
VideoSelector::m_categorySelector
MythUIButtonList * m_categorySelector
Definition: videoselector.h:88
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:212
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1590
mythuitext.h
MythUIText::Reset
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:83
ParentalLevel::plLowest
@ plLowest
Definition: parentalcontrols.h:12
VideoSelector::m_plotText
MythUIText * m_plotText
Definition: videoselector.h:91
mythdb.h
VideoSelector::haveResult
void haveResult(bool ok)
MythScreenType::Close
virtual void Close()
Definition: mythscreentype.cpp:385
RemoteFile::Exists
static bool Exists(const QString &url, struct stat *fileinfo)
Definition: remotefile.cpp:461
VideoSelector::m_warningText
MythUIText * m_warningText
Definition: videoselector.h:85
StorageGroup::FindFile
QString FindFile(const QString &filename)
Definition: storagegroup.cpp:602
MythUIImage::Load
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
Definition: mythuiimage.cpp:968
ParentalLevel::plMedium
@ plMedium
Definition: parentalcontrols.h:12
ParentalLevel::plHigh
@ plHigh
Definition: parentalcontrols.h:13
MythUIButtonList::itemSelected
void itemSelected(MythUIButtonListItem *item)
ParentalLevel::plLow
@ plLow
Definition: parentalcontrols.h:12
VideoSelector::toggleSelected
void toggleSelected(MythUIButtonListItem *item)
Definition: videoselector.cpp:172
mythdialogbox.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:202
MythScreenStack
Definition: mythscreenstack.h:16
MythUIButtonListItem::FullChecked
@ FullChecked
Definition: mythuibuttonlist.h:41
VideoSelector::m_selectedList
QList< VideoInfo * > m_selectedList
Definition: videoselector.h:79
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:607
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:44
VideoSelector::m_currentParentalLevel
ParentalLevel::Level m_currentParentalLevel
Definition: videoselector.h:81
VideoSelector::getVideoListFromDB
static std::vector< VideoInfo * > * getVideoListFromDB(void)
Definition: videoselector.cpp:369
VideoSelector::updateSelectedList
void updateSelectedList(void)
Definition: videoselector.cpp:514
ParentalLevelChangeChecker
Definition: parentalcontrols.h:43
mythuibuttonlist.h
VideoSelector::m_parentalLevelChecker
ParentalLevelChangeChecker * m_parentalLevelChecker
Definition: videoselector.h:75
mythuiimage.h
MythUIButtonList::GetCount
int GetCount() const
Definition: mythuibuttonlist.cpp:1655
VideoSelector::titleChanged
void titleChanged(MythUIButtonListItem *item)
Definition: videoselector.cpp:191
VideoSelector::m_titleText
MythUIText * m_titleText
Definition: videoselector.h:89
VideoSelector::cancelPressed
void cancelPressed(void)
Definition: videoselector.cpp:312
VideoSelector::m_videoList
std::vector< VideoInfo * > * m_videoList
Definition: videoselector.h:78
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:112
VideoSelector::selectAll
void selectAll(void)
Definition: videoselector.cpp:151
VideoInfo::id
int id
Definition: videoselector.h:28
VideoSelector::setParentalLevel
void setParentalLevel(ParentalLevel::Level level)
Definition: videoselector.cpp:535
MythUIButtonListItem
Definition: mythuibuttonlist.h:34
VideoSelector::Create
bool Create() override
Definition: videoselector.cpp:44
ArchiveItem::type
QString type
Definition: archiveutil.h:53
VideoSelector::m_archiveList
QList< ArchiveItem * > * m_archiveList
Definition: videoselector.h:77
VideoSelector::keyPressEvent
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
Definition: videoselector.cpp:93
VideoSelector::m_plText
MythUIText * m_plText
Definition: videoselector.h:83
MythUIType::Show
void Show(void)
Definition: mythuitype.cpp:1137
MythUIButtonList::itemClicked
void itemClicked(MythUIButtonListItem *item)
MythMainWindow::TranslateKeyPress
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
Definition: mythmainwindow.cpp:1102
remotefile.h
ParentalLevel::Level
Level
Definition: parentalcontrols.h:12
archiveutil.h
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:117
MythDialogBox
Basic menu dialog, message and a list of options.
Definition: mythdialogbox.h:166
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:539
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:205
VideoSelector::parentalLevelChanged
void parentalLevelChanged(bool passwordValid, ParentalLevel::Level newLevel)
Definition: videoselector.cpp:540
videoselector.h
VideoSelector::OKPressed
void OKPressed(void)
Definition: videoselector.cpp:240
VideoInfo
Definition: videoselector.h:26
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3648
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
ParentalLevelChangeChecker::SigResultReady
void SigResultReady(bool passwordValid, ParentalLevel::Level newLevel)
UIUtilDisp::Assign
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
VideoSelector::ShowMenu
void ShowMenu(void) override
Definition: videoselector.cpp:136
MythUIType::Hide
void Hide(void)
Definition: mythuitype.cpp:1132
VideoSelector::m_coverImage
MythUIImage * m_coverImage
Definition: videoselector.h:92
VideoSelector::m_okButton
MythUIButton * m_okButton
Definition: videoselector.h:86
MythScreenType::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythscreentype.cpp:397
ParentalLevelChangeChecker::Check
void Check(ParentalLevel::Level fromLevel, ParentalLevel::Level toLevel)
Definition: parentalcontrols.cpp:366
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:692
MythUIButtonList::GetValue
virtual QString GetValue() const
Definition: mythuibuttonlist.cpp:1609
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:133
VideoSelector::m_cancelButton
MythUIButton * m_cancelButton
Definition: videoselector.h:87
MythUIButtonListItem::state
CheckState state() const
Definition: mythuibuttonlist.cpp:3602
mythcontext.h
MythUIButtonList::Reset
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuibuttonlist.cpp:114
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:101
StorageGroup
Definition: storagegroup.h:11
VideoSelector::m_filesizeText
MythUIText * m_filesizeText
Definition: videoselector.h:90
MythUIButtonList::SetItemCurrent
void SetItemCurrent(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1557
build_compdb.action
action
Definition: build_compdb.py:9
mythuibutton.h
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:319
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:862
VideoSelector::VideoSelector
VideoSelector(MythScreenStack *parent, QList< ArchiveItem * > *archiveList)
Definition: videoselector.cpp:26
ArchiveItem
Definition: archiveutil.h:50
VideoSelector::~VideoSelector
~VideoSelector(void) override
Definition: videoselector.cpp:35
MythUIImage::SetFilename
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
Definition: mythuiimage.cpp:676
MythUIButtonList::GetItemFirst
MythUIButtonListItem * GetItemFirst() const
Definition: mythuibuttonlist.cpp:1636
build_compdb.filename
filename
Definition: build_compdb.py:21
mythmainwindow.h
MythUIButtonListItem::setChecked
void setChecked(CheckState state)
Definition: mythuibuttonlist.cpp:3612
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:50
VideoSelector::updateVideoList
void updateVideoList(void)
Definition: videoselector.cpp:318
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:558
VideoSelector::m_videoButtonList
MythUIButtonList * m_videoButtonList
Definition: videoselector.h:84
VideoSelector::getVideoList
void getVideoList(void)
Definition: videoselector.cpp:472
videoutils.h
MythUIButtonListItem::NotChecked
@ NotChecked
Definition: mythuibuttonlist.h:39
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:831