BibleTime
clexiconkeychooser.cpp
Go to the documentation of this file.
1 /*********
2 *
3 * In the name of the Father, and of the Son, and of the Holy Spirit.
4 *
5 * This file is part of BibleTime's source code, https://bibletime.info/
6 *
7 * Copyright 1999-2021 by the BibleTime developers.
8 * The BibleTime source code is licensed under the GNU General Public License
9 * version 2.0.
10 *
11 **********/
12 
13 #include "clexiconkeychooser.h"
14 
15 #include <algorithm>
16 #include <iterator>
17 #include <map>
18 #include <QBoxLayout>
19 #include <QComboBox>
20 #include <QHBoxLayout>
21 #include <QLayout>
22 #include <QStringList>
23 #include <Qt>
24 #include <utility>
25 #include "../../backend/drivers/btmodulelist.h"
26 #include "../../backend/drivers/cswordlexiconmoduleinfo.h"
27 #include "../../backend/drivers/cswordmoduleinfo.h"
28 #include "../../backend/keys/cswordkey.h"
29 #include "../../backend/keys/cswordldkey.h"
30 #include "../../util/btconnect.h"
31 #include "ckeychooserwidget.h"
32 
33 
35  CSwordKey * key,
36  QWidget * parent)
37  : CKeyChooser(parent)
38  , m_key(dynamic_cast<CSwordLDKey *>(key))
39 {
40  setModules(modules, false);
41 
42  //we use a layout because the key chooser should be resized to full size
43  auto * const l = new QHBoxLayout(this);
44  l->setSpacing(0);
45  l->setContentsMargins(0, 0, 0, 0);
46  l->setDirection(QBoxLayout::LeftToRight);
47  l->setSizeConstraint(QLayout::SetNoConstraint);
48 
49  m_widget = new CKeyChooserWidget(0, this);
50  setFocusProxy(m_widget);
51 
52  //don't allow a too high width, try to keep as narrow as possible
53  //to aid users with smaller screen resolutions
54  m_widget->comboBox().setMaximumWidth(200);
55 
57  tr("Entries of the current work"),
58  tr("Next entry"),
59  tr("Scroll through the entries of the list. Press the button and move the mouse to increase or decrease the item."),
60  tr("Previous entry")
61  );
62 
63  l->addWidget(m_widget, 0, Qt::AlignLeft);
64 
65  auto const activatedSlot =
66  [this](int index) {
67  if (m_key) {
68  auto text(m_widget->comboBox().itemText(index));
69  /* Check to prevent from eternal loop, because activated()
70  is emitted again: */
71  if (m_key->key() != text) {
72  m_key->setKey(std::move(text));
73  setKey(m_key);
74  }
75  }
76  };
79 
80  setModules(modules, true);
81  setKey(key);
82 }
83 
85  // qWarning("key");
86  return m_key;
87 }
88 
89 /** Update key display without emiting a signal */
91  if (!(m_key = dynamic_cast<CSwordLDKey*>(key))) {
92  return;
93  }
94 
95  QString newKey = m_key->key();
96  const int index = m_widget->comboBox().findText(newKey);
97  m_widget->comboBox().setCurrentIndex(index);
98 }
99 
101  if (!(m_key = dynamic_cast<CSwordLDKey*>(key))) {
102  return;
103  }
104 
105  updateKey(key);
106 
107  // qWarning("setKey end");
108  Q_EMIT keyChanged( m_key);
109 }
110 
111 /** Reimplementation. */
113  if (m_modules.count() == 1) {
114  m_widget->reset(&m_modules.first()->entries(), 0, true);
115  // qWarning("resetted");
116  }
117  else {
118  std::multimap<unsigned int, QStringList const *> entryMap;
119  for (auto const * const modulePtr : m_modules) {
120  auto const & entries = modulePtr->entries();
121  entryMap.emplace(entries.count(), &entries);
122  }
123 
124  QStringList goodEntries; //The string list which contains the entries which are available in all modules
125 
126  auto it(entryMap.begin()); // iterator to go though all selected modules
127  QStringList refEntries = *(it->second); //copy the items for the first time
128  const QStringList *cmpEntries = (++it)->second; //list for comparision, starts with the second module in the map
129 
130  // Testing for refEntries being empty is not needed for the set union
131  // of all keys, but is a good idea since it is being updated in the
132  // loop. It is necessary for set intersection and prevents a crash.
133  while (it != entryMap.end() && (refEntries.begin() != refEntries.end())) {
134  std::set_union(
135  refEntries.begin(), --(refEntries.end()), //--end() is the last valid entry
136  cmpEntries->begin(), --(cmpEntries->end()),
137  std::back_inserter(goodEntries) //append valid entries to the end of goodEntries
138  );
139 
140  cmpEntries = ( ++it )->second; //this is a pointer to the string list of a new module
141 
142  /*
143  * use the good entries for next comparision,
144  * because the final list can only have the entries of goodEntries as maxiumum
145  */
146  refEntries = goodEntries;
147  }
148 
149  m_widget->reset(goodEntries, 0, true); //write down the entries
150  } //end of ELSE
151 
152 }
153 
155  bool refresh)
156 {
157  using CSLMI = CSwordLexiconModuleInfo;
158 
159  while (!m_modules.isEmpty())
160  m_modules.takeFirst(); // not deleting the pointer
161 
162  for (auto const * const m : modules)
163  if (CSLMI const * const lexicon = dynamic_cast<CSLMI const *>(m))
164  m_modules.append(lexicon);
165 
166  if (refresh) {
167  refreshContent();
168  }
169 }
#define BT_CONNECT(...)
Definition: btconnect.h:20
QList< CSwordModuleInfo const * > BtConstModuleList
Definition: btmodulelist.h:21
void focusOut(int index)
void setToolTips(const QString &comboTip, const QString &nextEntry, const QString &scrollButton, const QString &previousEntry)
QComboBox & comboBox() const
void changed(int index)
void reset(const int count, int index, bool do_emit)
void keyChanged(CSwordKey *newKey)
QList< CSwordLexiconModuleInfo const * > m_modules
CSwordKey * key() final override
void setModules(BtConstModuleList const &modules, bool refresh=true) final override
void setKey(CSwordKey *key) final override
void refreshContent() final override
CKeyChooserWidget * m_widget
CLexiconKeyChooser(BtConstModuleList const &modules, CSwordKey *key=nullptr, QWidget *parent=nullptr)
void updateKey(CSwordKey *key) final override
bool setKey(const QString &newKey) final override
Definition: cswordldkey.cpp:86
QString key() const final override
Definition: cswordldkey.cpp:71