1 /* -*- c++ -*- */
2 /*
3  * Gqrx SDR: Software defined radio receiver powered by GNU Radio and Qt
4  *           https://gqrx.dk/
5  *
6  * Copyright 2013 Christian Lindner DL2VCL, Stefano Leucci.
7  *
8  * Gqrx is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3, or (at your option)
11  * any later version.
12  *
13  * Gqrx is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Gqrx; see the file COPYING.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street,
21  * Boston, MA 02110-1301, USA.
22  */
23 #include <cmath>
24 #include <cstdlib>
25 #include <QComboBox>
26 #include <QDialogButtonBox>
27 #include <QDir>
28 #include <QInputDialog>
29 #include <QMenu>
30 #include <QMessageBox>
31 
32 #include "bookmarks.h"
33 #include "bookmarkstaglist.h"
34 #include "dockbookmarks.h"
35 #include "dockrxopt.h"
36 #include "qtcolorpicker.h"
37 #include "ui_dockbookmarks.h"
38 
DockBookmarks(QWidget * parent)39 DockBookmarks::DockBookmarks(QWidget *parent) :
40     QDockWidget(parent),
41     ui(new Ui::DockBookmarks)
42 {
43     ui->setupUi(this);
44 
45     bookmarksTableModel = new BookmarksTableModel();
46 
47     // Frequency List
48     ui->tableViewFrequencyList->setModel(bookmarksTableModel);
49     ui->tableViewFrequencyList->setColumnWidth(BookmarksTableModel::COL_NAME,
50     ui->tableViewFrequencyList->columnWidth(BookmarksTableModel::COL_NAME) * 2);
51     ui->tableViewFrequencyList->setSelectionBehavior(QAbstractItemView::SelectRows);
52     ui->tableViewFrequencyList->setSelectionMode(QAbstractItemView::SingleSelection);
53     ui->tableViewFrequencyList->installEventFilter(this);
54 
55     // Demod Selection in Frequency List Table.
56     ComboBoxDelegateModulation* delegateModulation = new ComboBoxDelegateModulation(this);
57     ui->tableViewFrequencyList->setItemDelegateForColumn(2, delegateModulation);
58 
59     // Bookmarks Context menu
60     contextmenu = new QMenu(this);
61     // MenuItem Delete
62     {
63         QAction* action = new QAction("Delete Bookmark", this);
64         contextmenu->addAction(action);
65         connect(action, SIGNAL(triggered()), this, SLOT(DeleteSelectedBookmark()));
66     }
67     // MenuItem Add
68     {
69         actionAddBookmark = new QAction("Add Bookmark", this);
70         contextmenu->addAction(actionAddBookmark);
71     }
72     ui->tableViewFrequencyList->setContextMenuPolicy(Qt::CustomContextMenu);
73     connect(ui->tableViewFrequencyList, SIGNAL(customContextMenuRequested(const QPoint&)),
74         this, SLOT(ShowContextMenu(const QPoint&)));
75 
76     // Update GUI
77     Bookmarks::Get().load();
78     bookmarksTableModel->update();
79 
80     m_currentFrequency = 0;
81     m_updating = false;
82 
83     // TagList
84     updateTags();
85 
86     connect(ui->tableViewFrequencyList, SIGNAL(activated(const QModelIndex &)),
87             this, SLOT(activated(const QModelIndex &)));
88     connect(ui->tableViewFrequencyList, SIGNAL(doubleClicked(const QModelIndex &)),
89             this, SLOT(doubleClicked(const QModelIndex &)));
90     connect(bookmarksTableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
91             this, SLOT(onDataChanged(const QModelIndex &, const QModelIndex &)));
92     connect(&Bookmarks::Get(), SIGNAL(TagListChanged()),
93             ui->tableWidgetTagList, SLOT(updateTags()));
94     connect(&Bookmarks::Get(), SIGNAL(BookmarksChanged()),
95             bookmarksTableModel, SLOT(update()));
96 }
97 
~DockBookmarks()98 DockBookmarks::~DockBookmarks()
99 {
100     delete ui;
101     delete bookmarksTableModel;
102 }
103 
activated(const QModelIndex & index)104 void DockBookmarks::activated(const QModelIndex & index)
105 {
106     BookmarkInfo *info = bookmarksTableModel->getBookmarkAtRow(index.row());
107     emit newBookmarkActivated(info->frequency, info->modulation, info->bandwidth);
108 }
109 
setNewFrequency(qint64 rx_freq)110 void DockBookmarks::setNewFrequency(qint64 rx_freq)
111 {
112     ui->tableViewFrequencyList->clearSelection();
113     const int iRowCount = bookmarksTableModel->rowCount();
114     for (int row = 0; row < iRowCount; ++row)
115     {
116         BookmarkInfo& info = *(bookmarksTableModel->getBookmarkAtRow(row));
117         if (std::abs(rx_freq - info.frequency) <= ((info.bandwidth / 2 ) + 1))
118         {
119             ui->tableViewFrequencyList->selectRow(row);
120             ui->tableViewFrequencyList->scrollTo(ui->tableViewFrequencyList->currentIndex(), QAbstractItemView::EnsureVisible );
121             break;
122         }
123     }
124     m_currentFrequency = rx_freq;
125 }
126 
updateTags()127 void DockBookmarks::updateTags()
128 {
129     m_updating = true;
130     ui->tableWidgetTagList->updateTags();
131     m_updating = false;
132 }
133 
updateBookmarks()134 void DockBookmarks::updateBookmarks()
135 {
136     bookmarksTableModel->update();
137 }
138 
139 //Data has been edited
onDataChanged(const QModelIndex &,const QModelIndex &)140 void DockBookmarks::onDataChanged(const QModelIndex&, const QModelIndex &)
141 {
142     updateTags();
143     Bookmarks::Get().save();
144 }
145 
on_tableWidgetTagList_itemChanged(QTableWidgetItem * item)146 void DockBookmarks::on_tableWidgetTagList_itemChanged(QTableWidgetItem *item)
147 {
148     // we only want to react on changed by the user, not changes by the program itself.
149     if(ui->tableWidgetTagList->m_bUpdating) return;
150 
151     int col = item->column();
152     if (col != 1)
153         return;
154 
155     QString strText = item->text();
156     Bookmarks::Get().setTagChecked(strText, (item->checkState() == Qt::Checked));
157 }
158 
eventFilter(QObject * object,QEvent * event)159 bool DockBookmarks::eventFilter(QObject* object, QEvent* event)
160 {
161     if (event->type() == QEvent::KeyPress)
162     {
163         QKeyEvent* pKeyEvent = static_cast<QKeyEvent *>(event);
164         if (pKeyEvent->key() == Qt::Key_Delete && ui->tableViewFrequencyList->hasFocus())
165         {
166             return DeleteSelectedBookmark();
167         }
168     }
169     return QWidget::eventFilter(object, event);
170 }
171 
DeleteSelectedBookmark()172 bool DockBookmarks::DeleteSelectedBookmark()
173 {
174     QModelIndexList selected = ui->tableViewFrequencyList->selectionModel()->selectedRows();
175 
176     if (selected.empty())
177     {
178         return true;
179     }
180 
181     if (QMessageBox::question(this, "Delete bookmark", "Really delete?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
182     {
183         int iIndex = bookmarksTableModel->GetBookmarksIndexForRow(selected.first().row());
184         Bookmarks::Get().remove(iIndex);
185         bookmarksTableModel->update();
186     }
187     return true;
188 }
189 
ShowContextMenu(const QPoint & pos)190 void DockBookmarks::ShowContextMenu(const QPoint& pos)
191 {
192     contextmenu->popup(ui->tableViewFrequencyList->viewport()->mapToGlobal(pos));
193 }
194 
doubleClicked(const QModelIndex & index)195 void DockBookmarks::doubleClicked(const QModelIndex & index)
196 {
197     if(index.column() == BookmarksTableModel::COL_TAGS)
198     {
199         changeBookmarkTags(index.row(), index.column());
200     }
201 }
202 
ComboBoxDelegateModulation(QObject * parent)203 ComboBoxDelegateModulation::ComboBoxDelegateModulation(QObject *parent)
204 :QItemDelegate(parent)
205 {
206 }
207 
createEditor(QWidget * parent,const QStyleOptionViewItem &,const QModelIndex & index) const208 QWidget *ComboBoxDelegateModulation::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &index) const
209 {
210     QComboBox* comboBox = new QComboBox(parent);
211     for (int i = 0; i < DockRxOpt::ModulationStrings.size(); ++i)
212     {
213         comboBox->addItem(DockRxOpt::ModulationStrings[i]);
214     }
215     setEditorData(comboBox, index);
216     return comboBox;
217 }
218 
setEditorData(QWidget * editor,const QModelIndex & index) const219 void ComboBoxDelegateModulation::setEditorData(QWidget *editor, const QModelIndex &index) const
220 {
221     QComboBox *comboBox = static_cast<QComboBox*>(editor);
222     QString value = index.model()->data(index, Qt::EditRole).toString();
223     int iModulation = DockRxOpt::GetEnumForModulationString(value);
224     comboBox->setCurrentIndex(iModulation);
225 }
226 
setModelData(QWidget * editor,QAbstractItemModel * model,const QModelIndex & index) const227 void ComboBoxDelegateModulation::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
228 {
229     QComboBox *comboBox = static_cast<QComboBox*>(editor);
230     model->setData(index, comboBox->currentText(), Qt::EditRole);
231 }
232 
changeBookmarkTags(int row,int)233 void DockBookmarks::changeBookmarkTags(int row, int /*column*/)
234 {
235     bool ok = false;
236     QString tags; // list of tags separated by comma
237 
238     int iIdx = bookmarksTableModel->GetBookmarksIndexForRow(row);
239     BookmarkInfo& bmi = Bookmarks::Get().getBookmark(iIdx);
240 
241     // Create and show the Dialog for a new Bookmark.
242     // Write the result into variable 'tags'.
243     {
244         QDialog dialog(this);
245         dialog.setWindowTitle("Change Bookmark Tags");
246 
247         BookmarksTagList* taglist = new BookmarksTagList(&dialog, false);
248         taglist->updateTags();
249         taglist->setSelectedTags(bmi.tags);
250         taglist->DeleteTag(TagInfo::strUntagged);
251 
252         QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
253                                               | QDialogButtonBox::Cancel);
254         connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
255         connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
256 
257         QVBoxLayout *mainLayout = new QVBoxLayout(&dialog);
258         mainLayout->addWidget(taglist);
259         mainLayout->addWidget(buttonBox);
260 
261         ok = dialog.exec();
262         if (ok)
263         {
264             tags = taglist->getSelectedTagsAsString();
265             // list of selected tags is now in string 'tags'.
266 
267             // Change Tags of Bookmark
268             QStringList listTags = tags.split(",",QString::SkipEmptyParts);
269             bmi.tags.clear();
270             if (listTags.size() == 0)
271             {
272                 bmi.tags.append(&Bookmarks::Get().findOrAddTag("")); // "Untagged"
273             }
274             for (int i = 0; i < listTags.size(); ++i)
275             {
276                 bmi.tags.append(&Bookmarks::Get().findOrAddTag(listTags[i]));
277             }
278             Bookmarks::Get().save();
279         }
280     }
281 }
282