summaryrefslogtreecommitdiff
path: root/utils/regtools/qeditor/utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/regtools/qeditor/utils.cpp')
-rw-r--r--utils/regtools/qeditor/utils.cpp594
1 files changed, 527 insertions, 67 deletions
diff --git a/utils/regtools/qeditor/utils.cpp b/utils/regtools/qeditor/utils.cpp
index 0d0a7de5ed..748a989512 100644
--- a/utils/regtools/qeditor/utils.cpp
+++ b/utils/regtools/qeditor/utils.cpp
@@ -30,6 +30,9 @@
30#include <QXmlStreamWriter> 30#include <QXmlStreamWriter>
31#include <QTextBlock> 31#include <QTextBlock>
32#include <QApplication> 32#include <QApplication>
33#include <QPushButton>
34#include <QMessageBox>
35#include <QStandardItemModel>
33 36
34/** 37/**
35 * SocBitRangeValidator 38 * SocBitRangeValidator
@@ -406,6 +409,11 @@ bool SocFieldBitRange::operator<(const SocFieldBitRange& o) const
406 return m_last_bit < o.m_last_bit; 409 return m_last_bit < o.m_last_bit;
407} 410}
408 411
412bool SocFieldBitRange::operator!=(const SocFieldBitRange& o) const
413{
414 return m_first_bit != o.m_first_bit || m_last_bit != o.m_last_bit;
415}
416
409/** 417/**
410 * SocFieldCachedItemDelegate 418 * SocFieldCachedItemDelegate
411 */ 419 */
@@ -476,6 +484,53 @@ void SocFieldCachedEditor::setValue(SocFieldCachedValue val)
476} 484}
477 485
478/** 486/**
487 * SocAccessItemDelegate
488 */
489QString SocAccessItemDelegate::displayText(const QVariant& value, const QLocale& locale) const
490{
491 if(isUserType< soc_desc::access_t >(value))
492 {
493 soc_desc::access_t acc = value.value< soc_desc::access_t >();
494 switch(acc)
495 {
496 case soc_desc::UNSPECIFIED: return m_unspec_text;
497 case soc_desc::READ_ONLY: return "Read-Only";
498 case soc_desc::READ_WRITE: return "Read-Write";
499 case soc_desc::WRITE_ONLY: return "Write-Only";
500 default: return "<bug>";
501 }
502 }
503 else
504 return QStyledItemDelegate::displayText(value, locale);
505}
506
507/**
508 * SocAccessEditor
509 */
510SocAccessEditor::SocAccessEditor(const QString& unspec_text, QWidget *parent)
511 :QComboBox(parent)
512{
513 addItem(unspec_text, QVariant::fromValue(soc_desc::UNSPECIFIED));
514 addItem("Read-Only", QVariant::fromValue(soc_desc::READ_ONLY));
515 addItem("Read-Write", QVariant::fromValue(soc_desc::READ_WRITE));
516 addItem("Write-Only", QVariant::fromValue(soc_desc::WRITE_ONLY));
517}
518
519SocAccessEditor::~SocAccessEditor()
520{
521}
522
523soc_desc::access_t SocAccessEditor::access() const
524{
525 return itemData(currentIndex()).value< soc_desc::access_t >();
526}
527
528void SocAccessEditor::setAccess(soc_desc::access_t acc)
529{
530 setCurrentIndex(findData(QVariant::fromValue(acc)));
531}
532
533/**
479 * SocFieldEditorCreator 534 * SocFieldEditorCreator
480 */ 535 */
481QWidget *SocFieldEditorCreator::createWidget(QWidget *parent) const 536QWidget *SocFieldEditorCreator::createWidget(QWidget *parent) const
@@ -494,6 +549,19 @@ void SocFieldEditorCreator::setWidth(int bitcount)
494} 549}
495 550
496/** 551/**
552 * SocAccessEditorCreator
553 */
554QWidget *SocAccessEditorCreator::createWidget(QWidget *parent) const
555{
556 return new SocAccessEditor(m_unspec_text, parent);
557}
558
559QByteArray SocAccessEditorCreator::valuePropertyName() const
560{
561 return QByteArray("access");
562}
563
564/**
497 * SocFieldCachedEditorCreator 565 * SocFieldCachedEditorCreator
498 */ 566 */
499QWidget *SocFieldCachedEditorCreator::createWidget(QWidget *parent) const 567QWidget *SocFieldCachedEditorCreator::createWidget(QWidget *parent) const
@@ -602,8 +670,22 @@ bool RegFieldTableModel::setData(const QModelIndex& idx, const QVariant& value,
602 if(role != Qt::EditRole) 670 if(role != Qt::EditRole)
603 return false; 671 return false;
604 int section = idx.column(); 672 int section = idx.column();
673 if(section == BitRangeColumn)
674 {
675 if(idx.row() < 0 || idx.row() >= rowCount())
676 return false;
677 if(value.type() != QVariant::UserType && value.userType() == qMetaTypeId< SocFieldBitRange >())
678 return false;
679 SocFieldBitRange bitrange = value.value< SocFieldBitRange >();
680 m_reg.field[idx.row()].pos = bitrange.GetFirstBit();
681 m_reg.field[idx.row()].width = bitrange.GetLastBit() - bitrange.GetFirstBit() + 1;
682 emit OnBitrangeModified(idx.row());
683 }
605 if(section < FirstValueColumn || section >= FirstValueColumn + m_value.size()) 684 if(section < FirstValueColumn || section >= FirstValueColumn + m_value.size())
685 {
686 qDebug() << "ignore setData to column " << section;
606 return false; 687 return false;
688 }
607 section -= FirstValueColumn; 689 section -= FirstValueColumn;
608 const SocFieldCachedValue& v = value.value< SocFieldCachedValue >(); 690 const SocFieldCachedValue& v = value.value< SocFieldCachedValue >();
609 if(!m_value[section].isValid()) 691 if(!m_value[section].isValid())
@@ -622,7 +704,12 @@ Qt::ItemFlags RegFieldTableModel::flags(const QModelIndex& index) const
622 Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; 704 Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
623 int section = index.column(); 705 int section = index.column();
624 if(section < FirstValueColumn || section >= FirstValueColumn + m_value.size()) 706 if(section < FirstValueColumn || section >= FirstValueColumn + m_value.size())
707 {
708 /* bitrange or name */
709 if(!m_read_only)
710 flags |= Qt::ItemIsEditable;
625 return flags; 711 return flags;
712 }
626 section -= FirstValueColumn; 713 section -= FirstValueColumn;
627 if(m_value[section].isValid() && !m_read_only) 714 if(m_value[section].isValid() && !m_read_only)
628 flags |= Qt::ItemIsEditable; 715 flags |= Qt::ItemIsEditable;
@@ -764,6 +851,207 @@ bool RegFieldProxyModel::lessThan(const QModelIndex& left,
764} 851}
765 852
766/** 853/**
854 * YRegDisplayItemEditor
855 */
856YRegDisplayItemEditor::YRegDisplayItemEditor(QWidget *parent, YRegDisplay *display,
857 YRegDisplayItemDelegate *delegate, QModelIndex bitrange_index,
858 QModelIndex name_index)
859 :QWidget(parent), m_display_delegate(delegate),
860 m_display(display), m_state(Idle)
861{
862 m_col_width = m_display->BitrangeRect(SocFieldBitRange(0, 0)).width();
863 m_resize_margin = m_col_width / 4;
864 setEditorData(bitrange_index, name_index);
865 setMouseTracking(true);
866 setAutoFillBackground(true);
867 setFocusPolicy(Qt::StrongFocus); // QItemDelegate says it's important
868}
869
870void YRegDisplayItemEditor::setEditorData(QModelIndex bitrange_index, QModelIndex name_index)
871{
872 if(m_state != Idle)
873 {
874 m_state = Idle;
875 QApplication::restoreOverrideCursor();
876 }
877 m_bitrange_index = bitrange_index;
878 m_name_index = name_index;
879 m_bitrange = bitrange_index.data().value< SocFieldBitRange >();
880}
881
882void YRegDisplayItemEditor::getEditorData(QVariant& name, QVariant& bitrange)
883{
884 name = QVariant(); /* don't touch the name */
885 bitrange = QVariant::fromValue(m_bitrange);
886}
887
888YRegDisplayItemEditor::~YRegDisplayItemEditor()
889{
890 /* make sure to restore cursor if modified */
891 if(m_state != Idle)
892 {
893 m_state = Idle;
894 QApplication::restoreOverrideCursor();
895 }
896}
897
898YRegDisplayItemEditor::Zone YRegDisplayItemEditor::GetZone(const QPoint& pt)
899{
900 if(!rect().contains(pt))
901 return NoZone;
902 if(pt.x() >= 0 && pt.x() <= m_resize_margin)
903 return ResizeLeftZone;
904 if(pt.x() >= width() - m_resize_margin && pt.x() <= width())
905 return ResizeRightZone;
906 return MoveZone;
907}
908
909void YRegDisplayItemEditor::mouseMoveEvent(QMouseEvent *event)
910{
911 Zone zone = GetZone(event->pos());
912 bool in_resize_zone = (zone == ResizeLeftZone || zone == ResizeRightZone);
913 /* resizing/moving has priority */
914 if(m_state == ResizingLeft || m_state == ResizingRight || m_state == Moving)
915 {
916 SocFieldBitRange new_bitrange = m_bitrange;
917 if(m_state == Moving)
918 {
919 /* Compute new bitrange: we know the offset of the mouse relative to the
920 * left of the register: use that offset to compute the new position of
921 * the MSB bit. To make it more natural, add half of a column of margin
922 * so that the register does not move until half of a bit column displacement
923 * was made */
924 int bit = m_display->bitColumnAt(mapTo(m_display,
925 event->pos() - QPoint(m_move_offset - m_col_width / 2, 0)));
926 new_bitrange.SetLastBit(bit);
927 int w = m_bitrange.GetLastBit() - m_bitrange.GetFirstBit();
928 /* make sure range is valid */
929 if(bit - w < 0)
930 return;
931 new_bitrange.SetFirstBit(bit - w);
932 }
933 else
934 {
935 /* Compute new bitrange. To make it more natural, add quarter of a column of margin
936 * so that the register does not resize until quarter of a bit column displacement
937 * was made */
938 int bit = m_display->bitColumnAt(mapTo(m_display, event->pos()
939 + QPoint(m_col_width / 4, 0)));
940 if(m_state == ResizingLeft)
941 new_bitrange.SetLastBit(bit);
942 else
943 new_bitrange.SetFirstBit(bit);
944 /* make sure range is valid */
945 if(new_bitrange.GetLastBit() < new_bitrange.GetFirstBit())
946 return;
947 }
948 /* make sure range does not overlap with other fields */
949 /* TODO */
950 /* update current bitrange (display only) and resize widget */
951 if(m_bitrange != new_bitrange)
952 {
953 m_bitrange = new_bitrange;
954 /* resize widget */
955 QRect rect = m_display->BitrangeRect(m_bitrange);
956 rect.moveTopLeft(parentWidget()->mapFromGlobal(m_display->mapToGlobal(rect.topLeft())));
957 setGeometry(rect);
958 }
959 }
960 /* any zone -> resize zone */
961 else if(in_resize_zone)
962 {
963 /* don't do unnecessary changes */
964 if(m_state != InResizeZone)
965 {
966 /* restore old cursor if needed */
967 if(m_state != Idle)
968 QApplication::restoreOverrideCursor();
969 m_state = InResizeZone;
970 QApplication::setOverrideCursor(QCursor(Qt::SizeHorCursor));
971 }
972 }
973 /* any zone -> move zone */
974 else if(zone == MoveZone)
975 {
976 /* don't do unnecessary changes */
977 if(m_state != InMoveZone)
978 {
979 /* restore old cursor if needed */
980 if(m_state != Idle)
981 QApplication::restoreOverrideCursor();
982 m_state = InMoveZone;
983 QApplication::setOverrideCursor(QCursor(Qt::SizeAllCursor));
984 }
985 }
986 /* any zone -> no zone */
987 else if(zone == NoZone)
988 {
989 if(m_state != Idle)
990 {
991 m_state = Idle;
992 QApplication::restoreOverrideCursor();
993 }
994 }
995}
996
997void YRegDisplayItemEditor::leaveEvent(QEvent *event)
998{
999 Q_UNUSED(event);
1000 if(m_state == InResizeZone)
1001 {
1002 m_state = Idle;
1003 QApplication::restoreOverrideCursor();
1004 }
1005}
1006
1007void YRegDisplayItemEditor::mousePressEvent(QMouseEvent *event)
1008{
1009 /* just in case the mouseMove event was not done */
1010 mouseMoveEvent(event);
1011 /* we need to track mouse outside of widget but Qt already grabs the mouse
1012 * for us on mouse press in widget */
1013 if(m_state == InResizeZone)
1014 {
1015 if(GetZone(event->pos()) == ResizeLeftZone)
1016 m_state = ResizingLeft;
1017 else
1018 m_state = ResizingRight;
1019 }
1020 else if(m_state == InMoveZone)
1021 {
1022 m_state = Moving;
1023 /* store offset from the left, to keep relative position of the register
1024 * with respect to the mouse */
1025 m_move_offset = event->pos().x();
1026 }
1027}
1028
1029void YRegDisplayItemEditor::mouseReleaseEvent(QMouseEvent *event)
1030{
1031 if(m_state == ResizingLeft || m_state == ResizingRight || m_state == Moving)
1032 {
1033 QApplication::restoreOverrideCursor();
1034 m_state = Idle;
1035 /* update cursor */
1036 mouseMoveEvent(event);
1037 }
1038}
1039
1040void YRegDisplayItemEditor::paintEvent(QPaintEvent *event)
1041{
1042 Q_UNUSED(event);
1043 QPainter painter(this);
1044 /* reuse delegate code to paint */
1045 QStyleOptionViewItemV4 opt = m_display->viewOptions();
1046 opt.state |= QStyle::State_HasFocus | QStyle::State_Selected | QStyle::State_Active;
1047 opt.displayAlignment = Qt::AlignHCenter | Qt::AlignVCenter;
1048 opt.rect = rect();
1049 opt.showDecorationSelected = true;
1050 m_display_delegate->initStyleOption(&opt, m_name_index);
1051 m_display_delegate->MyPaint(&painter, opt);
1052}
1053
1054/**
767 * YRegDisplayItemDelegate 1055 * YRegDisplayItemDelegate
768 */ 1056 */
769 1057
@@ -772,14 +1060,9 @@ YRegDisplayItemDelegate::YRegDisplayItemDelegate(QObject *parent)
772{ 1060{
773} 1061}
774 1062
775 void YRegDisplayItemDelegate::paint(QPainter *painter, 1063void YRegDisplayItemDelegate::MyPaint(QPainter *painter, const QStyleOptionViewItemV4& option) const
776 const QStyleOptionViewItem& option, const QModelIndex& index) const
777{ 1064{
778 QStyleOptionViewItemV4 opt = option; 1065 QStyleOptionViewItemV4 opt = option;
779 // default alignment is centered unless specified
780 opt.displayAlignment = Qt::AlignHCenter | Qt::AlignVCenter;
781 initStyleOption(&opt, index);
782
783 painter->save(); 1066 painter->save();
784 // draw everything rotated, requires careful manipulation of the 1067 // draw everything rotated, requires careful manipulation of the
785 // rects involved 1068 // rects involved
@@ -789,17 +1072,58 @@ YRegDisplayItemDelegate::YRegDisplayItemDelegate(QObject *parent)
789 QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); 1072 QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
790 style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); 1073 style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget);
791 painter->restore(); 1074 painter->restore();
1075}
1076
1077void YRegDisplayItemDelegate::paint(QPainter *painter,
1078 const QStyleOptionViewItem& option, const QModelIndex& index) const
1079{
1080 QStyleOptionViewItemV4 opt = option;
1081 // default alignment is centered unless specified
1082 opt.displayAlignment = Qt::AlignHCenter | Qt::AlignVCenter;
1083 initStyleOption(&opt, index);
1084
1085 MyPaint(painter, opt);
792 1086
793} 1087}
794 1088
795QSize YRegDisplayItemDelegate::sizeHint(const QStyleOptionViewItem& option, 1089QSize YRegDisplayItemDelegate::sizeHint(const QStyleOptionViewItem& option,
796 const QModelIndex& index) const 1090 const QModelIndex& index) const
797{ 1091{
1092 /* useless in our case, the view ignores this */
798 Q_UNUSED(option); 1093 Q_UNUSED(option);
799 Q_UNUSED(index); 1094 Q_UNUSED(index);
800 return QSize(); 1095 return QSize();
801} 1096}
802 1097
1098QWidget *YRegDisplayItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option,
1099 const QModelIndex& index) const
1100{
1101 Q_UNUSED(option);
1102 Q_UNUSED(index);
1103 YRegDisplay *display = dynamic_cast< YRegDisplay* >(parent->parent());
1104 Q_ASSERT(display != nullptr);
1105 /* column 0 is name, column 1 is range */
1106 return new YRegDisplayItemEditor(parent, display, const_cast< YRegDisplayItemDelegate* >(this),
1107 index.sibling(index.row(), 0), index.sibling(index.row(), 1));
1108}
1109
1110void YRegDisplayItemDelegate::setEditorData(QWidget *editor, const QModelIndex& index) const
1111{
1112 dynamic_cast< YRegDisplayItemEditor* >(editor)->setEditorData(
1113 index.sibling(index.row(), 0), index.sibling(index.row(), 1));
1114}
1115
1116void YRegDisplayItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
1117 const QModelIndex& index) const
1118{
1119 QVariant name, bitrange;
1120 dynamic_cast< YRegDisplayItemEditor* >(editor)->getEditorData(name, bitrange);
1121 if(name.isValid())
1122 model->setData(index.sibling(index.row(), 1), name);
1123 if(bitrange.isValid())
1124 model->setData(index.sibling(index.row(), 0), bitrange);
1125}
1126
803/** 1127/**
804 * YRegDisplay 1128 * YRegDisplay
805 */ 1129 */
@@ -814,7 +1138,8 @@ YRegDisplay::YRegDisplay(QWidget *parent)
814 // the frame around the register is ugly, disable it 1138 // the frame around the register is ugly, disable it
815 setFrameShape(QFrame::NoFrame); 1139 setFrameShape(QFrame::NoFrame);
816 setSelectionMode(SingleSelection); 1140 setSelectionMode(SingleSelection);
817 setItemDelegate(new YRegDisplayItemDelegate()); 1141 setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);
1142 setItemDelegate(new YRegDisplayItemDelegate(this));
818} 1143}
819 1144
820void YRegDisplay::setWidth(int nr_bits) 1145void YRegDisplay::setWidth(int nr_bits)
@@ -1055,6 +1380,11 @@ QRect YRegDisplay::itemRect(const QModelIndex& index) const
1055 return itemRect(range, index.column()); 1380 return itemRect(range, index.column());
1056} 1381}
1057 1382
1383QRect YRegDisplay::BitrangeRect(const SocFieldBitRange& range) const
1384{
1385 return itemRect(range, m_data_col);
1386}
1387
1058QRect YRegDisplay::itemRect(const SocFieldBitRange& range, int col) const 1388QRect YRegDisplay::itemRect(const SocFieldBitRange& range, int col) const
1059{ 1389{
1060 int top, bot; 1390 int top, bot;
@@ -1276,17 +1606,17 @@ MyTextEditor::MyTextEditor(QWidget *parent)
1276 m_edit->setAutoFormatting(QTextEdit::AutoAll); 1606 m_edit->setAutoFormatting(QTextEdit::AutoAll);
1277 1607
1278 m_bold_button = new QToolButton(this); 1608 m_bold_button = new QToolButton(this);
1279 m_bold_button->setIcon(QIcon::fromTheme("format-text-bold")); 1609 m_bold_button->setIcon(YIconManager::Get()->GetIcon(YIconManager::FormatTextBold));
1280 m_bold_button->setText("bold"); 1610 m_bold_button->setText("bold");
1281 m_bold_button->setCheckable(true); 1611 m_bold_button->setCheckable(true);
1282 1612
1283 m_italic_button = new QToolButton(this); 1613 m_italic_button = new QToolButton(this);
1284 m_italic_button->setIcon(QIcon::fromTheme("format-text-italic")); 1614 m_italic_button->setIcon(YIconManager::Get()->GetIcon(YIconManager::FormatTextItalic));
1285 m_italic_button->setText("italic"); 1615 m_italic_button->setText("italic");
1286 m_italic_button->setCheckable(true); 1616 m_italic_button->setCheckable(true);
1287 1617
1288 m_underline_button = new QToolButton(this); 1618 m_underline_button = new QToolButton(this);
1289 m_underline_button->setIcon(QIcon::fromTheme("format-text-underline")); 1619 m_underline_button->setIcon(YIconManager::Get()->GetIcon(YIconManager::FormatTextUnderline));
1290 m_underline_button->setText("underline"); 1620 m_underline_button->setText("underline");
1291 m_underline_button->setCheckable(true); 1621 m_underline_button->setCheckable(true);
1292 1622
@@ -1419,10 +1749,13 @@ BackendSelector::BackendSelector(Backend *backend, QWidget *parent)
1419 :QWidget(parent), m_backend(backend) 1749 :QWidget(parent), m_backend(backend)
1420{ 1750{
1421 m_data_selector = new QComboBox(this); 1751 m_data_selector = new QComboBox(this);
1422 m_data_selector->addItem(QIcon::fromTheme("text-x-generic"), "Nothing...", QVariant(DataSelNothing)); 1752 m_data_selector->addItem(YIconManager::Get()->GetIcon(YIconManager::TextGeneric),
1423 m_data_selector->addItem(QIcon::fromTheme("document-open"), "File...", QVariant(DataSelFile)); 1753 "Nothing...", QVariant(DataSelNothing));
1754 m_data_selector->addItem(YIconManager::Get()->GetIcon(YIconManager::DocumentOpen),
1755 "File...", QVariant(DataSelFile));
1424#ifdef HAVE_HWSTUB 1756#ifdef HAVE_HWSTUB
1425 m_data_selector->addItem(QIcon::fromTheme("multimedia-player"), "Device...", QVariant(DataSelDevice)); 1757 m_data_selector->addItem(YIconManager::Get()->GetIcon(YIconManager::MultimediaPlayer),
1758 "USB Device...", QVariant(DataSelDevice));
1426#endif 1759#endif
1427 m_data_sel_edit = new QLineEdit(this); 1760 m_data_sel_edit = new QLineEdit(this);
1428 m_data_sel_edit->setReadOnly(true); 1761 m_data_sel_edit->setReadOnly(true);
@@ -1435,7 +1768,18 @@ BackendSelector::BackendSelector(Backend *backend, QWidget *parent)
1435 data_sel_layout->addStretch(0); 1768 data_sel_layout->addStretch(0);
1436#ifdef HAVE_HWSTUB 1769#ifdef HAVE_HWSTUB
1437 m_dev_selector = new QComboBox; 1770 m_dev_selector = new QComboBox;
1771 m_ctx_model = new HWStubContextModel;
1772 m_ctx_model->EnableDummy(true, "Please select a device...");
1773 m_dev_selector->setModel(m_ctx_model); /* m_dev_selector will delete m_ctx_model */
1774 m_ctx_selector = new QComboBox;
1775 m_ctx_manager = HWStubManager::Get();
1776 m_ctx_selector->setModel(m_ctx_manager);
1777 m_ctx_manage_button = new QPushButton();
1778 m_ctx_manage_button->setIcon(YIconManager::Get()->GetIcon(YIconManager::Preferences));
1779 m_ctx_manage_button->setToolTip("Manage contexts");
1438 data_sel_layout->addWidget(m_dev_selector, 1); 1780 data_sel_layout->addWidget(m_dev_selector, 1);
1781 data_sel_layout->addWidget(m_ctx_selector);
1782 data_sel_layout->addWidget(m_ctx_manage_button);
1439#endif 1783#endif
1440 1784
1441 m_io_backend = m_backend->CreateDummyIoBackend(); 1785 m_io_backend = m_backend->CreateDummyIoBackend();
@@ -1443,18 +1787,25 @@ BackendSelector::BackendSelector(Backend *backend, QWidget *parent)
1443 connect(m_data_selector, SIGNAL(activated(int)), 1787 connect(m_data_selector, SIGNAL(activated(int)),
1444 this, SLOT(OnDataSelChanged(int))); 1788 this, SLOT(OnDataSelChanged(int)));
1445#ifdef HAVE_HWSTUB 1789#ifdef HAVE_HWSTUB
1446 connect(m_dev_selector, SIGNAL(currentIndexChanged(int)), 1790 connect(m_ctx_selector, SIGNAL(currentIndexChanged(int)), this,
1447 this, SLOT(OnDevChanged(int))); 1791 SLOT(OnContextSelChanged(int)));
1448 connect(&m_hwstub_helper, SIGNAL(OnDevListChanged(bool, struct libusb_device *)), 1792 connect(m_dev_selector, SIGNAL(currentIndexChanged(int)), this,
1449 this, SLOT(OnDevListChanged2(bool, struct libusb_device *))); 1793 SLOT(OnDeviceSelChanged(int)));
1794 connect(m_dev_selector, SIGNAL(activated(int)), this,
1795 SLOT(OnDeviceSelActivated(int)));
1796#endif
1797
1798#ifdef HAVE_HWSTUB
1799 OnContextSelChanged(0);
1450#endif 1800#endif
1451 OnDataSelChanged(0); 1801 OnDataSelChanged(0);
1452} 1802}
1453 1803
1454BackendSelector::~BackendSelector() 1804BackendSelector::~BackendSelector()
1455{ 1805{
1806 /* avoid m_ctx_selector from deleting HWStubManager */
1456#ifdef HAVE_HWSTUB 1807#ifdef HAVE_HWSTUB
1457 ClearDevList(); 1808 m_ctx_selector->setModel(new QStandardItemModel());
1458#endif 1809#endif
1459 delete m_io_backend; 1810 delete m_io_backend;
1460} 1811}
@@ -1475,6 +1826,8 @@ void BackendSelector::OnDataSelChanged(int index)
1475 m_data_sel_edit->show(); 1826 m_data_sel_edit->show();
1476#ifdef HAVE_HWSTUB 1827#ifdef HAVE_HWSTUB
1477 m_dev_selector->hide(); 1828 m_dev_selector->hide();
1829 m_ctx_selector->hide();
1830 m_ctx_manage_button->hide();
1478#endif 1831#endif
1479 QFileDialog *fd = new QFileDialog(m_data_selector); 1832 QFileDialog *fd = new QFileDialog(m_data_selector);
1480 QStringList filters; 1833 QStringList filters;
@@ -1496,7 +1849,10 @@ void BackendSelector::OnDataSelChanged(int index)
1496 m_nothing_text->hide(); 1849 m_nothing_text->hide();
1497 m_data_sel_edit->hide(); 1850 m_data_sel_edit->hide();
1498 m_dev_selector->show(); 1851 m_dev_selector->show();
1499 OnDevListChanged(); 1852 m_ctx_selector->show();
1853 m_ctx_manage_button->show();
1854 /* explicitely change the backend now */
1855 OnDeviceSelActivated(m_dev_selector->currentIndex());
1500 } 1856 }
1501#endif 1857#endif
1502 else 1858 else
@@ -1505,83 +1861,68 @@ void BackendSelector::OnDataSelChanged(int index)
1505 m_nothing_text->show(); 1861 m_nothing_text->show();
1506#ifdef HAVE_HWSTUB 1862#ifdef HAVE_HWSTUB
1507 m_dev_selector->hide(); 1863 m_dev_selector->hide();
1864 m_ctx_selector->hide();
1865 m_ctx_manage_button->hide();
1508#endif 1866#endif
1509 1867
1510 ChangeBackend(m_backend->CreateDummyIoBackend()); 1868 ChangeBackend(m_backend->CreateDummyIoBackend());
1511 } 1869 }
1512} 1870}
1513 1871
1514#ifdef HAVE_HWSTUB 1872IoBackend *BackendSelector::GetBackend()
1515void BackendSelector::OnDevListChanged2(bool arrived, struct libusb_device *dev)
1516{ 1873{
1517 Q_UNUSED(arrived); 1874 return m_io_backend;
1518 Q_UNUSED(dev);
1519 OnDevListChanged();
1520} 1875}
1521 1876
1522void BackendSelector::OnDevListChanged() 1877void BackendSelector::ChangeBackend(IoBackend *new_backend)
1523{ 1878{
1524 ClearDevList(); 1879 /* WARNING: delete old backend *after* calling the signal, otherwise the old backend
1525 QList< HWStubDevice* > list = m_hwstub_helper.GetDevList(); 1880 * might get used after delete */
1526 foreach(HWStubDevice *dev, list) 1881 emit OnSelect(new_backend);
1527 { 1882 delete m_io_backend;
1528 QString name = QString("Bus %1 Device %2: %3").arg(dev->GetBusNumber()) 1883 m_io_backend = new_backend;
1529 .arg(dev->GetDevAddress()).arg(dev->GetTargetInfo().bName);
1530 m_dev_selector->addItem(QIcon::fromTheme("multimedia-player"), name,
1531 QVariant::fromValue((void *)dev));
1532 }
1533 if(list.size() > 0)
1534 m_dev_selector->setCurrentIndex(0);
1535} 1884}
1536 1885
1537void BackendSelector::OnDevChanged(int index) 1886#ifdef HAVE_HWSTUB
1887void BackendSelector::OnContextSelChanged(int index)
1538{ 1888{
1889 m_ctx_model->SetContext(m_ctx_manager->GetContext(index));
1890 m_dev_selector->setCurrentIndex(0);
1891}
1892
1893void BackendSelector::OnDeviceSelChanged(int index)
1894{
1895 /* if current selection is -1, because device was removed or a new context
1896 * was selected, select entry 0, which is dummy. Not that this will not
1897 * call activate(), we don't want to change the current backend if the user
1898 * is using another type of backend. */
1539 if(index == -1) 1899 if(index == -1)
1540 return; 1900 m_dev_selector->setCurrentIndex(0);
1541 HWStubDevice *dev = reinterpret_cast< HWStubDevice* >(m_dev_selector->itemData(index).value< void* >());
1542 delete m_io_backend;
1543 /* NOTE: make a copy of the HWStubDevice device because the one in the list
1544 * might get destroyed when clearing the list while the backend is still
1545 * active: this would result in a double free when the backend is also destroyed */
1546 m_io_backend = m_backend->CreateHWStubIoBackend(new HWStubDevice(dev));
1547 emit OnSelect(m_io_backend);
1548} 1901}
1549 1902
1550void BackendSelector::ClearDevList() 1903void BackendSelector::OnDeviceSelActivated(int index)
1551{ 1904{
1552 while(m_dev_selector->count() > 0) 1905 auto dev = new HWStubDevice(m_ctx_model->GetDevice(index));
1906 if(!dev->IsValid())
1553 { 1907 {
1554 HWStubDevice *dev = reinterpret_cast< HWStubDevice* >(m_dev_selector->itemData(0).value< void* >());
1555 delete dev; 1908 delete dev;
1556 m_dev_selector->removeItem(0); 1909 ChangeBackend(m_backend->CreateDummyIoBackend());
1557 } 1910 }
1911 else
1912 ChangeBackend(new HWStubIoBackend(dev));
1558} 1913}
1559#endif 1914#endif
1560 1915
1561IoBackend *BackendSelector::GetBackend()
1562{
1563 return m_io_backend;
1564}
1565
1566void BackendSelector::ChangeBackend(IoBackend *new_backend)
1567{
1568 /* WARNING: delete old backend *after* calling the signal, otherwise the old backend
1569 * might get used after delete */
1570 emit OnSelect(new_backend);
1571 delete m_io_backend;
1572 m_io_backend = new_backend;
1573}
1574
1575/** 1916/**
1576 * YTabWidget 1917 * YTabWidget
1577 */ 1918 */
1578YTabWidget::YTabWidget(QTabBar *bar, QWidget *parent) 1919YTabWidget::YTabWidget(QTabBar *bar, QWidget *parent)
1579 :QTabWidget(parent) 1920 :QTabWidget(parent), m_other_button(0)
1580{ 1921{
1581 if(bar != 0) 1922 if(bar != 0)
1582 setTabBar(bar); 1923 setTabBar(bar);
1583 m_tab_open_button = new QToolButton(this); 1924 m_tab_open_button = new QToolButton(this);
1584 m_tab_open_button->setIcon(QIcon::fromTheme("list-add")); 1925 m_tab_open_button->setIcon(YIconManager::Get()->GetIcon(YIconManager::ListAdd));
1585 m_tab_open_button->setAutoRaise(true); 1926 m_tab_open_button->setAutoRaise(true);
1586 m_tab_open_button->setPopupMode(QToolButton::InstantPopup); 1927 m_tab_open_button->setPopupMode(QToolButton::InstantPopup);
1587 /* the arrow with an icon only is pretty ugly and QToolButton has no way 1928 /* the arrow with an icon only is pretty ugly and QToolButton has no way
@@ -1592,8 +1933,8 @@ YTabWidget::YTabWidget(QTabBar *bar, QWidget *parent)
1592 connect(m_tab_open_button, SIGNAL(clicked(bool)), this, SLOT(OnOpenButton(bool))); 1933 connect(m_tab_open_button, SIGNAL(clicked(bool)), this, SLOT(OnOpenButton(bool)));
1593 /* there is a quirk in the default QStyle: if the tab bar is empty, it 1934 /* there is a quirk in the default QStyle: if the tab bar is empty, it
1594 * returns the minimum size of the corner widget, which is 0 for tool buttons */ 1935 * returns the minimum size of the corner widget, which is 0 for tool buttons */
1595 //setMinimumHeight(m_tab_open_button->height()); 1936 m_tab_open_button->setMinimumSize(m_tab_open_button->sizeHint());
1596 //m_tab_open_button->setMinimumHeight(m_tab_open_button->sizeHint().height()); 1937 setMinimumSize(m_tab_open_button->sizeHint());
1597} 1938}
1598 1939
1599void YTabWidget::setTabOpenable(bool openable) 1940void YTabWidget::setTabOpenable(bool openable)
@@ -1613,6 +1954,28 @@ void YTabWidget::setTabOpenMenu(QMenu *menu)
1613 m_tab_open_button->setMenu(menu); 1954 m_tab_open_button->setMenu(menu);
1614} 1955}
1615 1956
1957void YTabWidget::setOtherMenu(QMenu *menu)
1958{
1959 if(menu == nullptr)
1960 {
1961 if(m_other_button)
1962 delete m_other_button;
1963 m_other_button = nullptr;
1964 }
1965 else
1966 {
1967 if(m_other_button == nullptr)
1968 {
1969 m_other_button = new QToolButton(this);
1970 m_other_button->setText("Menu");
1971 m_other_button->setAutoRaise(true);
1972 m_other_button->setPopupMode(QToolButton::InstantPopup);
1973 setCornerWidget(m_other_button, Qt::TopRightCorner);
1974 }
1975 m_other_button->setMenu(menu);
1976 }
1977}
1978
1616/** 1979/**
1617 * MessageWidget 1980 * MessageWidget
1618 */ 1981 */
@@ -1625,6 +1988,7 @@ MessageWidget::MessageWidget(QWidget *parent)
1625 m_icon->hide(); 1988 m_icon->hide();
1626 m_text = new QLabel(this); 1989 m_text = new QLabel(this);
1627 m_text->setTextFormat(Qt::RichText); 1990 m_text->setTextFormat(Qt::RichText);
1991 m_text->setWordWrap(true);
1628 m_close = new QToolButton(this); 1992 m_close = new QToolButton(this);
1629 m_close->setText("close"); 1993 m_close->setText("close");
1630 m_close->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton)); 1994 m_close->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton));
@@ -1702,6 +2066,102 @@ void MessageWidget::OnClose(bool clicked)
1702 hide(); 2066 hide();
1703} 2067}
1704 2068
2069/*
2070 * YIconManager
2071 */
2072YIconManager *YIconManager::m_singleton = nullptr;
2073
2074YIconManager::YIconManager()
2075{
2076 m_icon_name[ListAdd] = "list-add";
2077 m_icon_name[ListRemove] = "list-remove";
2078 m_icon_name[DocumentNew] = "document-new";
2079 m_icon_name[DocumentEdit] = "document-edit";
2080 m_icon_name[DocumentOpen] = "document-open";
2081 m_icon_name[DocumentSave] = "document-save";
2082 m_icon_name[DocumentSaveAs] = "document-save-as";
2083 m_icon_name[Preferences] = "preferences-system";
2084 m_icon_name[FolderNew] = "folder-new";
2085 m_icon_name[Computer] = "computer";
2086 m_icon_name[Cpu] = "cpu";
2087 m_icon_name[DialogError] = "dialog-error";
2088 m_icon_name[ViewRefresh] = "view-refresh";
2089 m_icon_name[SytemRun] = "system-run";
2090 m_icon_name[ApplicationExit] = "application-exit";
2091 m_icon_name[HelpAbout] = "help-about";
2092 m_icon_name[FormatTextBold] = "format-text-bold";
2093 m_icon_name[FormatTextItalic] = "format-text-italic";
2094 m_icon_name[FormatTextUnderline] = "format-text-underline";
2095 m_icon_name[TextGeneric] = "text-x-generic";
2096 m_icon_name[MultimediaPlayer] = "multimedia-player";
2097}
2098
2099YIconManager::~YIconManager()
2100{
2101}
2102
2103YIconManager *YIconManager::Get()
2104{
2105 if(m_singleton == nullptr)
2106 m_singleton = new YIconManager();
2107 return m_singleton;
2108}
2109
2110QIcon YIconManager::GetIcon(IconType type)
2111{
2112 if(type < 0 || type >= MaxIcon)
2113 return QIcon();
2114 if(QIcon::hasThemeIcon(m_icon_name[type]))
2115 return QIcon::fromTheme(m_icon_name[type]);
2116 /* render icon if needed */
2117 if(m_icon[type].isNull())
2118 Render(type);
2119 return m_icon[type];
2120}
2121
2122namespace
2123{
2124 void RenderListAdd(QIcon& icon)
2125 {
2126 QPixmap pix(64, 64);
2127 pix.fill(Qt::transparent);
2128 QPainter paint(&pix);
2129 paint.fillRect(30, 12, 4, 40, QColor(255, 0, 0));
2130 paint.fillRect(12, 30, 40, 4, QColor(255, 0, 0));
2131 icon = QIcon(pix);
2132 }
2133
2134 void RenderListRemove(QIcon& icon)
2135 {
2136 QPixmap pix(64, 64);
2137 pix.fill(Qt::transparent);
2138 QPainter paint(&pix);
2139 paint.setPen(QColor(255, 0, 0));
2140 paint.drawLine(12, 12, 52, 52);
2141 paint.drawLine(12, 52, 52, 16);
2142 icon = QIcon(pix);
2143 }
2144
2145 void RenderUnknown(QIcon& icon)
2146 {
2147 QPixmap pix(64, 64);
2148 pix.fill();
2149 QPainter paint(&pix);
2150 paint.fillRect(0, 0, 64, 64, QColor(255, 0, 0));
2151 icon = QIcon(pix);
2152 }
2153}
2154
2155void YIconManager::Render(IconType type)
2156{
2157 switch(type)
2158 {
2159 case ListAdd: RenderListAdd(m_icon[type]); break;
2160 case ListRemove: RenderListRemove(m_icon[type]); break;
2161 default: RenderUnknown(m_icon[type]); break;
2162 }
2163}
2164
1705/** 2165/**
1706 * Misc 2166 * Misc
1707 */ 2167 */