diff --git a/utils/imxtools/misc/map.h b/utils/imxtools/misc/map.h index b94875ff6d..6143f91912 100644 --- a/utils/imxtools/misc/map.h +++ b/utils/imxtools/misc/map.h @@ -79,7 +79,7 @@ struct soc_t #define PIN_GROUP_PREFIX_NONE "" #define R(group,name,block) {PIN_GROUP_PREFIX_##group name, PIN_GROUP_##group, block} -#define Q(group,block,name) R(group,STR(block)"_"name, block) +#define Q(group,block,name) R(group,STR(block) "_" name, block) #define P(group,name) R(group,name,PIN_NO_BLOCK) #define IO P(GPIO,"gpio") diff --git a/utils/regtools/qeditor/backend.cpp b/utils/regtools/qeditor/backend.cpp index 5f006b0aa7..a8264c6e50 100644 --- a/utils/regtools/qeditor/backend.cpp +++ b/utils/regtools/qeditor/backend.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "backend.h" /** @@ -336,111 +337,437 @@ QString FileIoBackend::GetFileName() } #ifdef HAVE_HWSTUB +/** + * HWStubManager + */ +HWStubManager *HWStubManager::g_inst = nullptr; + +HWStubManager::HWStubManager() +{ + Add("Default", QString::fromStdString(hwstub::uri::default_uri().full_uri())); +} + +HWStubManager::~HWStubManager() +{ +} + +HWStubManager *HWStubManager::Get() +{ + if(g_inst == nullptr) + g_inst = new HWStubManager(); + return g_inst; +} + +bool HWStubManager::Add(const QString& name, const QString& uri) +{ + struct Context ctx; + ctx.name = name; + ctx.uri = uri; + ctx.context = hwstub::uri::create_context(uri.toStdString()); + if(!ctx.context) + return false; + ctx.context->start_polling(); + beginInsertRows(QModelIndex(), m_list.size(), m_list.size()); + m_list.push_back(ctx); + endInsertRows(); + return true; +} + +void HWStubManager::Clear() +{ + m_list.clear(); +} + +int HWStubManager::rowCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent); + return m_list.size(); +} + +int HWStubManager::columnCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent); + return 2; +} + +std::shared_ptr< hwstub::context > HWStubManager::GetContext(int row) +{ + if(row < 0 || (size_t)row >= m_list.size()) + return std::shared_ptr< hwstub::context >(); + else + return m_list[row].context; +} + +QVariant HWStubManager::data(const QModelIndex& index, int role) const +{ + if(index.row() < 0 || (size_t)index.row() >= m_list.size()) + return QVariant(); + int section = index.column(); + const Context& ctx = m_list[index.row()]; + if(section == GetNameColumn()) + { + if(role == Qt::DisplayRole || role == Qt::EditRole) + return QVariant(ctx.name); + } + else if(section == GetUriColumn()) + { + if(role == Qt::DisplayRole) + return QVariant(ctx.uri); + } + return QVariant(); +} + +QVariant HWStubManager::headerData(int section, Qt::Orientation orientation, int role) const +{ + if(orientation == Qt::Vertical) + return QVariant(); + if(role != Qt::DisplayRole) + return QVariant(); + if(section == GetNameColumn()) + return QVariant("Name"); + else if(section == GetUriColumn()) + return QVariant("URI"); + return QVariant(); +} + +Qt::ItemFlags HWStubManager::flags(const QModelIndex& index) const +{ + Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + int section = index.column(); + if(section == GetNameColumn()) + flags |= Qt::ItemIsEditable; + return flags; +} + +bool HWStubManager::setData(const QModelIndex& index, const QVariant& value, int role) +{ + if(role != Qt::EditRole) + return false; + if(index.row() < 0 || (size_t)index.row() >= m_list.size()) + return false; + if(index.column() != GetNameColumn()) + return false; + m_list[index.row()].name = value.toString(); + emit dataChanged(index, index); + return true; +} + +int HWStubManager::GetNameColumn() const +{ + return 0; +} + +int HWStubManager::GetUriColumn() const +{ + return 1; +} + +QString HWStubManager::GetFriendlyName(std::shared_ptr< hwstub::device > device) +{ + /* try to open the device */ + std::shared_ptr< hwstub::handle > handle; + hwstub::error err = device->open(handle); + if(err != hwstub::error::SUCCESS) + goto Lfallback; + /* get target descriptor */ + struct hwstub_target_desc_t target_desc; + err = handle->get_target_desc(target_desc); + if(err != hwstub::error::SUCCESS) + goto Lfallback; + return QString::fromStdString(target_desc.bName); + + /* fallback: don't open the device */ +Lfallback: + hwstub::usb::device *udev = dynamic_cast< hwstub::usb::device* >(device.get()); + if(udev) + { + return QString("USB Bus %1 Device %2: ID %3:%4") + .arg(udev->get_bus_number()).arg(udev->get_address(), 3, 10, QChar('0')) + .arg(udev->get_vid(), 4, 16, QChar('0')).arg(udev->get_pid(), 4, 16, QChar('0')); + } + else + return QString(""); +} + +/** + * HWStubContextModel + */ +HWStubContextModel::HWStubContextModel(QObject *parent) + :QAbstractTableModel(parent), m_has_dummy(false) +{ +} + +HWStubContextModel::~HWStubContextModel() +{ + SetContext(std::shared_ptr< hwstub::context >()); +} + +void HWStubContextModel::SetContext(std::shared_ptr< hwstub::context > context) +{ + int first_row = m_has_dummy ? 1: 0; + /* clear previous model if any */ + if(m_list.size() > 0) + { + beginRemoveRows(QModelIndex(), first_row, first_row + m_list.size() - 1); + m_list.clear(); + endRemoveRows(); + } + /* don't forget to unregister callback if context still exists */ + std::shared_ptr< hwstub::context > ctx = m_context.lock(); + if(ctx) + ctx->unregister_callback(m_callback_ref); + /* get new context */ + m_context = context; + if(context) + { + /* register new callback */ + m_callback_ref = context->register_callback( + std::bind(&HWStubContextModel::OnDevChangeLow, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)); + /* get dev list */ + std::vector< std::shared_ptr< hwstub::device > > list; + hwstub::error err = context->get_device_list(list); + if(err == hwstub::error::SUCCESS) + { + beginInsertRows(QModelIndex(), first_row, first_row + list.size() - 1); + for(auto& d : list) + { + Device dev; + dev.name = GetFriendlyName(d); + dev.device = d; + m_list.push_back(dev); + } + endInsertRows(); + } + } +} + +void HWStubContextModel::EnableDummy(bool en, const QString& text) +{ + /* if needed, create/remove raw */ + if(m_has_dummy && !en) + { + /* remove row */ + beginRemoveRows(QModelIndex(), 0, 0); + m_has_dummy = false; + endRemoveRows(); + } + else if(!m_has_dummy && en) + { + /* add row */ + beginInsertRows(QModelIndex(), 0, 0); + m_has_dummy = true; + m_dummy_text = text; + endInsertRows(); + } + else if(en) + { + /* text change only */ + emit dataChanged(index(0, GetNameColumn()), index(0, GetNameColumn())); + } +} + +int HWStubContextModel::rowCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent); + return m_list.size() + (m_has_dummy ? 1 : 0); +} + +int HWStubContextModel::columnCount(const QModelIndex& parent) const +{ + Q_UNUSED(parent); + return 1; +} + +QVariant HWStubContextModel::data(const QModelIndex& index, int role) const +{ + int first_row = m_has_dummy ? 1: 0; + /* special case for dummy */ + if(m_has_dummy && index.row() == 0) + { + int section = index.column(); + if(section == GetNameColumn()) + { + if(role == Qt::DisplayRole) + return QVariant(m_dummy_text); + else if(role == Qt::FontRole) + { + QFont font; + font.setItalic(true); + return QVariant(font); + } + } + return QVariant(); + } + + if(index.row() < first_row || (size_t)index.row() >= first_row + m_list.size()) + return QVariant(); + int section = index.column(); + if(section == GetNameColumn()) + { + if(role == Qt::DisplayRole) + return QVariant(m_list[index.row() - first_row].name); + } + return QVariant(); +} + +QVariant HWStubContextModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if(orientation == Qt::Vertical) + return QVariant(); + if(role != Qt::DisplayRole) + return QVariant(); + if(section == GetNameColumn()) + return QVariant("Friendly name"); + return QVariant(); +} + +Qt::ItemFlags HWStubContextModel::flags(const QModelIndex& index) const +{ + Q_UNUSED(index); + return Qt::ItemIsSelectable | Qt::ItemIsEnabled; +} + +int HWStubContextModel::GetNameColumn() const +{ + return 0; +} + +std::shared_ptr< hwstub::device > HWStubContextModel::GetDevice(int row) +{ + int first_row = m_has_dummy ? 1: 0; + /* special case for dummy */ + if(row < first_row || (size_t)row >= first_row + m_list.size()) + return std::shared_ptr< hwstub::device >(); + else + return m_list[row - first_row].device; +} + +QString HWStubContextModel::GetFriendlyName(std::shared_ptr< hwstub::device > device) +{ + return HWStubManager::GetFriendlyName(device); +} + +namespace +{ + struct dev_change_t + { + std::shared_ptr< hwstub::context > ctx; + bool arrived; + std::shared_ptr< hwstub::device > device; + }; +} + +void HWStubContextModel::OnDevChangeLow(std::shared_ptr< hwstub::context > ctx, + bool arrived, std::shared_ptr< hwstub::device > device) +{ + /* calling Qt function from non-Qt thread is unsafe. Since the polling thread + * is a pthread, the safest way to use Qt invoke mecanism to make it run + * on the event loop */ + dev_change_t *evt = new dev_change_t; + evt->ctx = ctx; + evt->arrived = arrived; + evt->device = device; + QMetaObject::invokeMethod(this, "OnDevChangeUnsafe", Q_ARG(void *, (void *)evt)); +} + +void HWStubContextModel::OnDevChangeUnsafe(void *data) +{ + dev_change_t *evt = (dev_change_t *)data; + OnDevChange(evt->ctx, evt->arrived, evt->device); + delete evt; +} + +void HWStubContextModel::OnDevChange(std::shared_ptr< hwstub::context > ctx, bool arrived, + std::shared_ptr< hwstub::device > device) +{ + int first_row = m_has_dummy ? 1: 0; + Q_UNUSED(ctx); + if(arrived) + { + Device dev; + dev.name = GetFriendlyName(device); + dev.device = device; + beginInsertRows(QModelIndex(), first_row + m_list.size(), + first_row + m_list.size()); + m_list.push_back(dev); + endInsertRows(); + } + else + { + /* find device in the list */ + auto it = m_list.begin(); + int idx = 0; + for(; it != m_list.end(); ++it, ++idx) + if(it->device == device) + break; + if(it == m_list.end()) + return; + /* remove it */ + beginRemoveRows(QModelIndex(), first_row + idx, first_row + idx); + m_list.erase(it); + endRemoveRows(); + } +} + /** * HWStubDevice */ -HWStubDevice::HWStubDevice(struct libusb_device *dev) +HWStubDevice::HWStubDevice(std::shared_ptr< hwstub::device > device) { - Init(dev); -} - -HWStubDevice::HWStubDevice(const HWStubDevice *dev) -{ - Init(dev->m_dev); -} - -void HWStubDevice::Init(struct libusb_device *dev) -{ - libusb_ref_device(dev); - m_dev = dev; - m_handle = 0; - m_hwdev = 0; - m_valid = Probe(); + m_valid = Probe(device); } HWStubDevice::~HWStubDevice() { - Close(); - libusb_unref_device(m_dev); } -int HWStubDevice::GetBusNumber() +bool HWStubDevice::Probe(std::shared_ptr device) { - return libusb_get_bus_number(m_dev); -} - -int HWStubDevice::GetDevAddress() -{ - return libusb_get_device_address(m_dev); -} - -bool HWStubDevice::Probe() -{ - if(!Open()) + if(!device) return false; - // get target - int ret = hwstub_get_desc(m_hwdev, HWSTUB_DT_TARGET, &m_hwdev_target, sizeof(m_hwdev_target)); - if(ret != sizeof(m_hwdev_target)) - goto Lerr; - // get STMP information + hwstub::error err = device->open(m_handle); + if(err != hwstub::error::SUCCESS) + return false; + // get target information + err = m_handle->get_target_desc(m_hwdev_target); + if(err != hwstub::error::SUCCESS) + return false; + // get STMP/PP information if(m_hwdev_target.dID == HWSTUB_TARGET_STMP) { - ret = hwstub_get_desc(m_hwdev, HWSTUB_DT_STMP, &m_hwdev_stmp, sizeof(m_hwdev_stmp)); - if(ret != sizeof(m_hwdev_stmp)) - goto Lerr; + err = m_handle->get_stmp_desc(m_hwdev_stmp); + if(err != hwstub::error::SUCCESS) + return false; } else if(m_hwdev_target.dID == HWSTUB_TARGET_PP) { - ret = hwstub_get_desc(m_hwdev, HWSTUB_DT_PP, &m_hwdev_pp, sizeof(m_hwdev_pp)); - if(ret != sizeof(m_hwdev_pp)) - goto Lerr; + err = m_handle->get_pp_desc(m_hwdev_pp); + if(err != hwstub::error::SUCCESS) + return false; } - Close(); - return true; - - Lerr: - Close(); - return false; -} - -bool HWStubDevice::Open() -{ - if(libusb_open(m_dev, &m_handle)) - return false; - m_hwdev = hwstub_open(m_handle); - if(m_hwdev == 0) + else if(m_hwdev_target.dID == HWSTUB_TARGET_JZ) { - libusb_close(m_handle); - m_handle = 0; - return false; + err = m_handle->get_jz_desc(m_hwdev_jz); + if(err != hwstub::error::SUCCESS) + return false; } + m_name = HWStubManager::GetFriendlyName(device); return true; } -void HWStubDevice::Close() -{ - if(m_hwdev) - hwstub_release(m_hwdev); - m_hwdev = 0; - if(m_handle) - libusb_close(m_handle); - m_handle = 0; -} - bool HWStubDevice::ReadMem(soc_addr_t addr, size_t length, void *buffer) { - if(!m_hwdev) - return false; - int ret = hwstub_rw_mem_atomic(m_hwdev, 1, addr, buffer, length); - return ret >= 0 && (size_t)ret == length; + size_t len = length; + hwstub::error err = m_handle->read(addr, buffer, len, true); + return err == hwstub::error::SUCCESS && len == length; } bool HWStubDevice::WriteMem(soc_addr_t addr, size_t length, void *buffer) { - if(!m_hwdev) - return false; - int ret = hwstub_rw_mem_atomic(m_hwdev, 0, addr, buffer, length); - return ret >= 0 && (size_t)ret == length; + size_t len = length; + hwstub::error err = m_handle->write(addr, buffer, len, true); + return err == hwstub::error::SUCCESS && len == length; } bool HWStubDevice::IsValid() @@ -448,6 +775,10 @@ bool HWStubDevice::IsValid() return m_valid; } +QString HWStubDevice::GetFriendlyName() +{ + return m_name; +} /** * HWStubIoBackend @@ -456,7 +787,7 @@ bool HWStubDevice::IsValid() HWStubIoBackend::HWStubIoBackend(HWStubDevice *dev) { m_dev = dev; - m_dev->Open(); + struct hwstub_target_desc_t target = m_dev->GetTargetInfo(); if(target.dID == HWSTUB_TARGET_STMP) { @@ -470,6 +801,13 @@ HWStubIoBackend::HWStubIoBackend(HWStubDevice *dev) else m_soc = QString("stmp%1").arg(stmp.wChipID, 4, 16, QChar('0')); } + else if(target.dID == HWSTUB_TARGET_JZ) + { + struct hwstub_jz_desc_t jz = m_dev->GetJZInfo(); + m_soc = QString("jz%1").arg(jz.wChipID, 4, 16, QChar('0')); + if(jz.bRevision != 0) + m_soc.append(QChar(jz.bRevision).toLower()); + } else if(target.dID == HWSTUB_TARGET_RK27) m_soc = "rk27x"; else if(target.dID == HWSTUB_TARGET_PP) @@ -549,95 +887,6 @@ bool HWStubIoBackend::Reload() return true; } -/** - * HWStubBackendHelper - */ -HWStubBackendHelper::HWStubBackendHelper() -{ -#ifdef LIBUSB_NO_HOTPLUG - m_hotplug = false; -#else - m_hotplug = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG); - if(m_hotplug) - { - int evt = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT; - m_hotplug = LIBUSB_SUCCESS == libusb_hotplug_register_callback( - NULL, (libusb_hotplug_event)evt, LIBUSB_HOTPLUG_ENUMERATE, - LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, - &HWStubBackendHelper::HotPlugCallback, reinterpret_cast< void* >(this), - &m_hotplug_handle); - } -#endif /* LIBUSB_NO_HOTPLUG */ -} - -HWStubBackendHelper::~HWStubBackendHelper() -{ -#ifndef LIBUSB_NO_HOTPLUG - if(m_hotplug) - libusb_hotplug_deregister_callback(NULL, m_hotplug_handle); -#endif /* LIBUSB_NO_HOTPLUG */ -} - -QList< HWStubDevice* > HWStubBackendHelper::GetDevList() -{ - QList< HWStubDevice* > list; - libusb_device **dev_list; - ssize_t cnt = hwstub_get_device_list(NULL, &dev_list); - for(int i = 0; i < cnt; i++) - { - HWStubDevice *dev = new HWStubDevice(dev_list[i]); - /* filter out non-hwstub devices */ - if(dev->IsValid()) - list.push_back(dev); - else - delete dev; - } - libusb_free_device_list(dev_list, 1); - return list; -} - -#ifndef LIBUSB_NO_HOTPLUG -void HWStubBackendHelper::OnHotPlug(bool arrived, struct libusb_device *dev) -{ - /* signal it */ - emit OnDevListChanged(arrived, dev); -} - -int HWStubBackendHelper::HotPlugCallback(struct libusb_context *ctx, struct libusb_device *dev, - libusb_hotplug_event event, void *user_data) -{ - Q_UNUSED(ctx); - HWStubBackendHelper *helper = reinterpret_cast< HWStubBackendHelper* >(user_data); - switch(event) - { - case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: helper->OnHotPlug(true, dev); break; - case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: helper->OnHotPlug(false, dev); break; - default: break; - } - return 0; -} -#endif /* LIBUSB_NO_HOTPLUG */ - -bool HWStubBackendHelper::HasHotPlugSupport() -{ - return m_hotplug; -} - -namespace -{ -class lib_usb_init -{ -public: - lib_usb_init() - { - libusb_init(NULL); - } -}; - -lib_usb_init __lib_usb_init; -} - #endif /* HAVE_HWSTUB */ /** diff --git a/utils/regtools/qeditor/backend.h b/utils/regtools/qeditor/backend.h index 17eeb44533..19e2cb5616 100644 --- a/utils/regtools/qeditor/backend.h +++ b/utils/regtools/qeditor/backend.h @@ -28,7 +28,9 @@ #include #include #ifdef HAVE_HWSTUB -#include "hwstub.h" +#include "hwstub.hpp" +#include "hwstub_usb.hpp" +#include "hwstub_uri.hpp" #endif #include "soc_desc.hpp" @@ -139,41 +141,124 @@ protected: }; #ifdef HAVE_HWSTUB +/* HWStub context manager: provides a centralized place to add/remove/get + * contexts */ +class HWStubManager : public QAbstractTableModel +{ + Q_OBJECT +protected: + HWStubManager(); +public: + virtual ~HWStubManager(); + /* Get manager */ + static HWStubManager *Get(); + /* Clear the context list */ + void Clear(); + bool Add(const QString& name, const QString& uri); + /* Model */ + virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex& index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual Qt::ItemFlags flags(const QModelIndex& index) const; + virtual bool setData(const QModelIndex& index, const QVariant& value, int role); + /* return predefined columns */ + int GetNameColumn() const; + int GetUriColumn() const; + std::shared_ptr< hwstub::context > GetContext(int row); + /* return a friendly name for a device */ + static QString GetFriendlyName(std::shared_ptr< hwstub::device > device); + +protected: + struct Context + { + std::shared_ptr< hwstub::context > context; + QString name; + QString uri; + }; + + std::vector< Context > m_list; /* list of context */ + static HWStubManager *g_inst; /* unique instance */ +}; + +/* HWStub context model: provides access to the device list using Qt MVC model. */ +class HWStubContextModel : public QAbstractTableModel +{ + Q_OBJECT +public: + HWStubContextModel(QObject *parent = 0); + virtual ~HWStubContextModel(); + void SetContext(std::shared_ptr< hwstub::context > context); + /* Model */ + virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex& index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual Qt::ItemFlags flags(const QModelIndex& index) const; + /* return predefined columns */ + int GetNameColumn() const; + std::shared_ptr< hwstub::device > GetDevice(int row); + /* Add an entry in the model for "no selection", which will correspond to + * a dummy device. This function also allows the text to be customised. */ + void EnableDummy(bool en, const QString& text = ""); + +private slots: + void OnDevChangeUnsafe(void *data); +protected: + QString GetFriendlyName(std::shared_ptr< hwstub::device > device); + void OnDevChangeLow(std::shared_ptr< hwstub::context > ctx, bool arrived, + std::shared_ptr< hwstub::device > device); + void OnDevChange(std::shared_ptr< hwstub::context > ctx, bool arrived, + std::shared_ptr< hwstub::device > device); + + struct Device + { + QString name; + std::shared_ptr< hwstub::device > device; + }; + + std::vector< Device > m_list; + std::weak_ptr< hwstub::context > m_context; + hwstub::context::callback_ref_t m_callback_ref; + bool m_has_dummy; + QString m_dummy_text; +}; + +/* Abstract Virtual Class from where TCP and USB backend + * child classes are derived + */ class HWStubDevice { public: - HWStubDevice(struct libusb_device *dev); - HWStubDevice(const HWStubDevice *dev); - ~HWStubDevice(); + HWStubDevice(std::shared_ptr device); + virtual ~HWStubDevice(); + + QString GetFriendlyName(); bool IsValid(); - bool Open(); - void Close(); - int GetBusNumber(); - int GetDevAddress(); - /* Calls below are cached and do not require the device to be opened */ + /* Calls below are cached */ inline struct hwstub_version_desc_t GetVersionInfo() { return m_hwdev_ver; } inline struct hwstub_target_desc_t GetTargetInfo() { return m_hwdev_target; } inline struct hwstub_stmp_desc_t GetSTMPInfo() { return m_hwdev_stmp; } inline struct hwstub_pp_desc_t GetPPInfo() { return m_hwdev_pp; } - /* Calls below require the device to be opened */ + inline struct hwstub_jz_desc_t GetJZInfo() { return m_hwdev_jz; } bool ReadMem(soc_addr_t addr, size_t length, void *buffer); bool WriteMem(soc_addr_t addr, size_t length, void *buffer); protected: - bool Probe(); - void Init(struct libusb_device *dev); + bool Probe(std::shared_ptr device); + std::shared_ptr m_handle; bool m_valid; - struct libusb_device *m_dev; - libusb_device_handle *m_handle; struct hwstub_device_t *m_hwdev; struct hwstub_version_desc_t m_hwdev_ver; struct hwstub_target_desc_t m_hwdev_target; struct hwstub_stmp_desc_t m_hwdev_stmp; struct hwstub_pp_desc_t m_hwdev_pp; + struct hwstub_jz_desc_t m_hwdev_jz; + QString m_name; }; -/** NOTE the HWStub backend is never dirty: all writes are immediately committed */ +/** NOTE the HWStub backend is never dirty: all wrnew ites are immediately committed */ class HWStubIoBackend : public IoBackend { Q_OBJECT @@ -197,32 +282,6 @@ protected: QString m_soc; HWStubDevice *m_dev; }; - -#if LIBUSB_API_VERSION < 0x01000102 -#define LIBUSB_NO_HOTPLUG -#endif - -class HWStubBackendHelper : public QObject -{ - Q_OBJECT -public: - HWStubBackendHelper(); - ~HWStubBackendHelper(); - bool HasHotPlugSupport(); - QList< HWStubDevice* > GetDevList(); - -signals: - void OnDevListChanged(bool arrived, struct libusb_device *dev); - -protected: -#ifndef LIBUSB_NO_HOTPLUG - void OnHotPlug(bool arrived, struct libusb_device *dev); - static int HotPlugCallback(struct libusb_context *ctx, struct libusb_device *dev, - libusb_hotplug_event event, void *user_data); - libusb_hotplug_callback_handle m_hotplug_handle; -#endif - bool m_hotplug; -}; #endif class SocFile diff --git a/utils/regtools/qeditor/mainwindow.cpp b/utils/regtools/qeditor/mainwindow.cpp index 8b83be6bae..69138a91b7 100644 --- a/utils/regtools/qeditor/mainwindow.cpp +++ b/utils/regtools/qeditor/mainwindow.cpp @@ -107,12 +107,18 @@ void DocumentTabWidget::OnCloseTab(int index) MainWindow::MainWindow(Backend *backend) :m_backend(backend) { - QAction *new_regtab_act = new QAction(QIcon::fromTheme("document-new"), tr("Register &Tab"), this); - QAction *new_regedit_act = new QAction(QIcon::fromTheme("document-edit"), tr("Register &Editor"), this); - QAction *load_desc_act = new QAction(QIcon::fromTheme("document-open"), tr("&Soc Description"), this); - QAction *quit_act = new QAction(QIcon::fromTheme("application-exit"), tr("&Quit"), this); - QAction *about_act = new QAction(QIcon::fromTheme("help-about"), tr("&About"), this); - QAction *about_qt_act = new QAction(QIcon::fromTheme("help-about"), tr("About &Qt"), this); + QAction *new_regtab_act = new QAction(YIconManager::Get()->GetIcon(YIconManager::DocumentNew), + tr("Register &Tab"), this); + QAction *new_regedit_act = new QAction(YIconManager::Get()->GetIcon(YIconManager::DocumentEdit), + tr("Register &Editor"), this); + QAction *load_desc_act = new QAction(YIconManager::Get()->GetIcon(YIconManager::DocumentOpen), + tr("&Soc Description"), this); + QAction *quit_act = new QAction(YIconManager::Get()->GetIcon(YIconManager::ApplicationExit), + tr("&Quit"), this); + QAction *about_act = new QAction(YIconManager::Get()->GetIcon(YIconManager::HelpAbout), + tr("&About"), this); + QAction *about_qt_act = new QAction(YIconManager::Get()->GetIcon(YIconManager::HelpAbout), + tr("About &Qt"), this); connect(new_regtab_act, SIGNAL(triggered()), this, SLOT(OnNewRegTab())); connect(new_regedit_act, SIGNAL(triggered()), this, SLOT(OnNewRegEdit())); @@ -121,9 +127,10 @@ MainWindow::MainWindow(Backend *backend) connect(about_act, SIGNAL(triggered()), this, SLOT(OnAbout())); connect(about_qt_act, SIGNAL(triggered()), this, SLOT(OnAboutQt())); - QMenu *file_menu = menuBar()->addMenu(tr("&File")); - QMenu *new_submenu = file_menu->addMenu(QIcon::fromTheme("document-new"), "&New"); - QMenu *load_submenu = file_menu->addMenu(QIcon::fromTheme("document-open"), "&Load"); + QMenu *app_menu = new QMenu; + QMenu *file_menu = app_menu->addMenu(tr("&File")); + QMenu *new_submenu = file_menu->addMenu(YIconManager::Get()->GetIcon(YIconManager::DocumentNew), "&New"); + QMenu *load_submenu = file_menu->addMenu(YIconManager::Get()->GetIcon(YIconManager::DocumentOpen), "&Load"); file_menu->addAction(quit_act); new_submenu->addAction(new_regtab_act); @@ -131,17 +138,24 @@ MainWindow::MainWindow(Backend *backend) load_submenu->addAction(load_desc_act); - QMenu *about_menu = menuBar()->addMenu(tr("&About")); + QMenu *about_menu = app_menu->addMenu(tr("&About")); about_menu->addAction(about_act); about_menu->addAction(about_qt_act); m_tab = new DocumentTabWidget(); m_tab->setTabOpenable(true); m_tab->setTabOpenMenu(new_submenu); + m_tab->setOtherMenu(app_menu); setCentralWidget(m_tab); ReadSettings(); +#ifdef HAVE_HWSTUB + /* acquire hwstub manager */ + HWStubManager::Get()->setParent(this); +#endif + /* acquire icon manager */ + YIconManager::Get()->setParent(this); OnNewRegTab(); } @@ -167,12 +181,12 @@ void MainWindow::OnAbout() .arg(soc_desc::MINOR_VERSION).arg(soc_desc::REVISION_VERSION); QMessageBox::about(this, "About", "

QEditor

" - "

Version "APP_VERSION"

" + "

Version " APP_VERSION "

" "

Written by Amaury Pouly

" "

Libraries:

" "
  • soc_desc: " + soc_desc_ver + "
  • " #ifdef HAVE_HWSTUB - "
  • hwstub: "HWSTUB_VERSION"
  • " + "
  • hwstub: " HWSTUB_VERSION "
  • " #else "
  • hwstub: not compiled in
  • " #endif diff --git a/utils/regtools/qeditor/qeditor.pro b/utils/regtools/qeditor/qeditor.pro index 0ec7c3dde1..5414f34e72 100644 --- a/utils/regtools/qeditor/qeditor.pro +++ b/utils/regtools/qeditor/qeditor.pro @@ -5,8 +5,9 @@ HEADERS += mainwindow.h backend.h regtab.h analyser.h settings.h \ SOURCES += main.cpp mainwindow.cpp regtab.cpp backend.cpp analyser.cpp \ std_analysers.cpp settings.cpp utils.cpp regdisplaypanel.cpp regedit.cpp LIBS += -L../lib/ -lsocdesc -lxml2 -INCLUDEPATH += ../include/ ../../hwstub/lib +INCLUDEPATH += ../include/ ../../hwstub/include DEPENDPATH += ../ +CONFIG += c++11 libsocdesc.commands = cd ../lib && make QMAKE_EXTRA_TARGETS += libsocdesc diff --git a/utils/regtools/qeditor/regdisplaypanel.cpp b/utils/regtools/qeditor/regdisplaypanel.cpp index a72d280d6c..1c2f1db9a9 100644 --- a/utils/regtools/qeditor/regdisplaypanel.cpp +++ b/utils/regtools/qeditor/regdisplaypanel.cpp @@ -46,7 +46,7 @@ SocDisplayPanel::SocDisplayPanel(QWidget *parent, IoBackend *io_backend, right_layout->addWidget(m_desc, 0); right_layout->addStretch(1); - setTitle("System-on-Chip Description"); + setTitle(""); setLayout(right_layout); } @@ -108,7 +108,7 @@ NodeDisplayPanel::NodeDisplayPanel(QWidget *parent, IoBackend *io_backend, right_layout->addWidget(m_inst_desc, 0); right_layout->addStretch(1); - setTitle("Device Description"); + setTitle(""); setLayout(right_layout); } @@ -126,6 +126,21 @@ QWidget *NodeDisplayPanel::GetWidget() * RegDisplayPanel */ +namespace +{ + QString access_string(soc_desc::access_t acc, QString dflt = "") + { + switch(acc) + { + case soc_desc::UNSPECIFIED: return dflt; + case soc_desc::READ_ONLY: return "Read only"; + case soc_desc::READ_WRITE: return "Read-write"; + case soc_desc::WRITE_ONLY: return "Write-only"; + default: return ""; + } + } +} + RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend, const soc_desc::node_inst_t& ref) :QGroupBox(parent), m_io_backend(io_backend), m_node(ref), m_reg_font(font()) @@ -139,16 +154,18 @@ RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend, m_reg_font.setKerning(false); QString reg_name = helper.GetPath(ref); - QStringList names; + QStringList names, access; QVector< soc_addr_t > addresses; names.append(reg_name); addresses.append(ref.addr()); + access.append(access_string(ref.node().reg().get()->access)); std::vector< soc_desc::variant_ref_t > variants = ref.node().reg().variants(); for(size_t i = 0; i < variants.size(); i++) { names.append(reg_name + "/" + QString::fromStdString(variants[i].get()->type)); addresses.append(ref.addr() + variants[i].get()->offset); + access.append(access_string(ref.node().reg().get()->access, access[0])); } QString str; @@ -169,10 +186,20 @@ RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend, label_addr->setTextFormat(Qt::RichText); label_addr->setText(str_addr); + QString str_acc; + str_acc += ""; + for(int i = 0; i < names.size(); i++) + str_acc += ""; + str_acc += "
    " + access[i] + "
    "; + QLabel *label_access = new QLabel; + label_access->setTextFormat(Qt::RichText); + label_access->setText(str_acc); + QHBoxLayout *top_layout = new QHBoxLayout; top_layout->addStretch(); top_layout->addWidget(label_names); top_layout->addWidget(label_addr); + top_layout->addWidget(label_access); top_layout->addStretch(); m_raw_val_name = new QLabel; @@ -250,7 +277,7 @@ RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend, right_layout->addWidget(m_value_table); right_layout->addStretch(); - setTitle("Register Description"); + setTitle(""); m_viewport = new QWidget; m_viewport->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_viewport->setLayout(right_layout); diff --git a/utils/regtools/qeditor/regedit.cpp b/utils/regtools/qeditor/regedit.cpp index 826452fdbd..bf86792c1e 100644 --- a/utils/regtools/qeditor/regedit.cpp +++ b/utils/regtools/qeditor/regedit.cpp @@ -107,14 +107,15 @@ SocEditPanel::SocEditPanel(const soc_desc::soc_ref_t& ref, QWidget *parent) for(size_t i = 0; i < authors.size(); i++) { QTableWidgetItem *item = new QTableWidgetItem( - QIcon::fromTheme("list-remove"), "", SocEditPanelDelType); + YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", SocEditPanelDelType); + item->setToolTip("Remove this author"); item->setFlags(Qt::ItemIsEnabled); m_authors_list->setItem(i, 0, item); item = new QTableWidgetItem(QString::fromStdString(authors[i])); m_authors_list->setItem(i, 1, item); } QTableWidgetItem *new_item = new QTableWidgetItem( - QIcon::fromTheme("list-add"), "", SocEditPanelAddType); + YIconManager::Get()->GetIcon(YIconManager::ListAdd), "", SocEditPanelAddType); new_item->setFlags(Qt::ItemIsEnabled); m_authors_list->setItem(authors.size(), 0, new_item); new_item = new QTableWidgetItem("New author...", QTableWidgetItem::UserType); @@ -188,7 +189,8 @@ void SocEditPanel::OnAuthorActivated(QTableWidgetItem *item) m_ref.get()->author.push_back("Anonymous"); m_authors_list->insertRow(row); QTableWidgetItem *item = new QTableWidgetItem( - QIcon::fromTheme("list-remove"), "", SocEditPanelDelType); + YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", SocEditPanelDelType); + item->setToolTip("Remove this author"); item->setFlags(Qt::ItemIsEnabled); m_authors_list->setItem(row, 0, item); item = new QTableWidgetItem(QString::fromStdString(m_ref.get()->author.back())); @@ -386,7 +388,8 @@ NodeInstanceEditPanel::NodeInstanceEditPanel(const soc_desc::node_ref_t& ref, for(size_t i = 0; i < addrs.size(); i++) { QTableWidgetItem *item = new QTableWidgetItem( - QIcon::fromTheme("list-remove"), "", NodeInstEditPanelDelType); + YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", NodeInstEditPanelDelType); + item->setToolTip("Remove this address"); item->setFlags(Qt::ItemIsEnabled); addr_list->setItem(i, 0, item); item = new QTableWidgetItem(); @@ -394,7 +397,7 @@ NodeInstanceEditPanel::NodeInstanceEditPanel(const soc_desc::node_ref_t& ref, addr_list->setItem(i, 1, item); } QTableWidgetItem *new_item = new QTableWidgetItem( - QIcon::fromTheme("list-add"), "", NodeInstEditPanelAddType); + YIconManager::Get()->GetIcon(YIconManager::ListAdd), "", NodeInstEditPanelAddType); new_item->setFlags(Qt::ItemIsEnabled); addr_list->setItem(addrs.size(), 0, new_item); new_item = new QTableWidgetItem("New address...", QTableWidgetItem::UserType); @@ -535,7 +538,8 @@ void NodeInstanceEditPanel::OnAddressActivated(QTableWidgetItem *item) GetInstance().range.list.push_back(new_addr); table->insertRow(row); QTableWidgetItem *item = new QTableWidgetItem( - QIcon::fromTheme("list-remove"), "", NodeInstEditPanelDelType); + YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", NodeInstEditPanelDelType); + item->setToolTip("Remove this address"); item->setFlags(Qt::ItemIsEnabled); table->setItem(row, 0, item); item = new QTableWidgetItem(); @@ -828,7 +832,8 @@ RegFieldEditPanel::RegFieldEditPanel(const soc_desc::field_ref_t& ref, QWidget * for(size_t i = 0; i < field.enum_.size(); i++) { QTableWidgetItem *item = new QTableWidgetItem( - QIcon::fromTheme("list-remove"), "", RegFieldEditPanelDelType); + YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", RegFieldEditPanelDelType); + item->setToolTip("Remove this enum"); item->setFlags(Qt::ItemIsEnabled); m_enum_table->setItem(i, 0, item); item = new QTableWidgetItem(QString::fromStdString(field.enum_[i].name)); @@ -840,7 +845,7 @@ RegFieldEditPanel::RegFieldEditPanel(const soc_desc::field_ref_t& ref, QWidget * m_enum_table->setItem(i, 3, item); } QTableWidgetItem *new_item = new QTableWidgetItem( - QIcon::fromTheme("list-add"), "", RegFieldEditPanelAddType); + YIconManager::Get()->GetIcon(YIconManager::ListAdd), "", RegFieldEditPanelAddType); new_item->setFlags(Qt::ItemIsEnabled); m_enum_table->setItem(field.enum_.size(), 0, new_item); new_item = new QTableWidgetItem("New field..."); @@ -875,6 +880,13 @@ void RegFieldEditPanel::UpdateWidth() m_range_validator->setWidth(m_ref.reg().get()->width); } +void RegFieldEditPanel::UpdateRange() +{ + soc_desc::field_t *field = m_ref.get(); + m_range_edit->setText(m_range_validator->generate( + field->pos + field->width - 1, field->pos)); +} + void RegFieldEditPanel::OnFieldValueActivated(QTableWidgetItem *item) { if(item->type() == RegFieldEditPanelDelType) @@ -895,7 +907,8 @@ void RegFieldEditPanel::OnFieldValueActivated(QTableWidgetItem *item) field.enum_.push_back(new_enum); m_enum_table->insertRow(row); QTableWidgetItem *item = new QTableWidgetItem( - QIcon::fromTheme("list-remove"), "", RegFieldEditPanelDelType); + YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", RegFieldEditPanelDelType); + item->setToolTip("Remove this enum"); item->setFlags(Qt::ItemIsEnabled); m_enum_table->setItem(row, 0, item); item = new QTableWidgetItem(QString::fromStdString(new_enum.name)); @@ -977,7 +990,7 @@ RegEditPanel::RegEditPanel(const soc_desc::register_ref_t& ref, QWidget *parent) m_value_model = new RegFieldTableModel(this); // view takes ownership m_value_model->SetRegister(*ref.get()); - m_value_model->SetReadOnly(true); + m_value_model->SetReadOnly(false); m_sexy_display2 = new Unscroll(this); m_sexy_display2->setFont(m_reg_font); @@ -1016,29 +1029,61 @@ RegEditPanel::RegEditPanel(const soc_desc::register_ref_t& ref, QWidget *parent) width_group_layout->addWidget(reg_size_32); width_group_layout->addWidget(reg_size_16); width_group_layout->addWidget(reg_size_8); - width_group_layout->addStretch(0); QGroupBox *width_group = new QGroupBox("Width"); width_group->setLayout(width_group_layout); + m_reg_access_group = new QButtonGroup(this); + QRadioButton *reg_dflt = new QRadioButton("Unspecified"); + QRadioButton *reg_rw = new QRadioButton("Read-Write"); + QRadioButton *reg_ro = new QRadioButton("Read-Only"); + QRadioButton *reg_wo = new QRadioButton("Write-Only"); + m_reg_access_group->addButton(reg_dflt, soc_desc::UNSPECIFIED); + m_reg_access_group->addButton(reg_rw, soc_desc::READ_WRITE); + m_reg_access_group->addButton(reg_ro, soc_desc::READ_ONLY); + m_reg_access_group->addButton(reg_wo, soc_desc::WRITE_ONLY); + if(m_reg_access_group->button(m_ref.get()->access)) + m_reg_access_group->button(m_ref.get()->access)->click(); + QVBoxLayout *access_group_layout = new QVBoxLayout; + access_group_layout->addWidget(reg_dflt); + access_group_layout->addWidget(reg_rw); + access_group_layout->addWidget(reg_ro); + access_group_layout->addWidget(reg_wo); + QGroupBox *access_group = new QGroupBox("Access"); + access_group->setLayout(access_group_layout); + + QVBoxLayout *width_access_layout = new QVBoxLayout; + width_access_layout->addWidget(width_group); + width_access_layout->addWidget(access_group); + width_access_layout->addStretch(0); + m_variant_table = new QTableWidget; - m_variant_table->setColumnCount(3); + m_variant_table->setColumnCount(4); m_variant_table->setHorizontalHeaderItem(0, new QTableWidgetItem("")); m_variant_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Type")); m_variant_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Offset")); + m_variant_table->setHorizontalHeaderItem(3, new QTableWidgetItem("Access")); m_variant_table->verticalHeader()->setVisible(false); m_variant_table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_variant_delegate = new SocFieldItemDelegate(this); m_variant_delegate->setItemEditorFactory(new QItemEditorFactory); - m_variant_editor = new SocFieldEditorCreator; - m_variant_delegate->itemEditorFactory()->registerEditor(QVariant::UInt, m_variant_editor); + m_variant_delegate->itemEditorFactory()->registerEditor(QVariant::UInt, + new SocFieldEditorCreator); m_variant_table->setItemDelegate(m_variant_delegate); + m_access_delegate = new SocAccessItemDelegate("Unspecified", this); + m_access_delegate->setItemEditorFactory(new QItemEditorFactory); + // FIXME see QTBUG-30392 + m_access_delegate->itemEditorFactory()->registerEditor( + (QVariant::Type)qMetaTypeId< soc_desc::access_t >(), + new SocAccessEditorCreator); + m_variant_table->setItemDelegateForColumn(3, m_access_delegate); std::vector< soc_desc::variant_ref_t > variants = m_ref.variants(); m_variant_table->setRowCount(variants.size() + 1); for(size_t i = 0; i < variants.size(); i++) { QTableWidgetItem *item = new QTableWidgetItem( - QIcon::fromTheme("list-remove"), "", RegVariantEditPanelDelType); + YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", RegVariantEditPanelDelType); + item->setToolTip("Remove this variant"); item->setFlags(Qt::ItemIsEnabled); m_variant_table->setItem(i, 0, item); item = new QTableWidgetItem(QString::fromStdString(variants[i].get()->type)); @@ -1046,9 +1091,12 @@ RegEditPanel::RegEditPanel(const soc_desc::register_ref_t& ref, QWidget *parent) item = new QTableWidgetItem(); item->setData(Qt::EditRole, QVariant(variants[i].get()->offset)); m_variant_table->setItem(i, 2, item); + item = new QTableWidgetItem(); + item->setData(Qt::EditRole, QVariant::fromValue(variants[i].get()->access)); + m_variant_table->setItem(i, 3, item); } QTableWidgetItem *new_item = new QTableWidgetItem( - QIcon::fromTheme("list-add"), "", RegVariantEditPanelAddType); + YIconManager::Get()->GetIcon(YIconManager::ListAdd), "", RegVariantEditPanelAddType); new_item->setFlags(Qt::ItemIsEnabled); m_variant_table->setItem(variants.size(), 0, new_item); new_item = new QTableWidgetItem("New variant..."); @@ -1069,7 +1117,7 @@ RegEditPanel::RegEditPanel(const soc_desc::register_ref_t& ref, QWidget *parent) m_desc_edit->SetTextHtml(QString::fromStdString(ref.get()->desc)); QHBoxLayout *top_info_layout = new QHBoxLayout; - top_info_layout->addWidget(width_group); + top_info_layout->addLayout(width_access_layout); top_info_layout->addWidget(Misc::EncloseInBox("Variants", m_variant_table)); top_info_layout->addWidget(Misc::EncloseInBox("Description", m_desc_edit)); @@ -1087,9 +1135,9 @@ RegEditPanel::RegEditPanel(const soc_desc::register_ref_t& ref, QWidget *parent) main_layout->addWidget(m_view_tab, 2); m_delete_action = new QAction("&Delete", this); - m_delete_action->setIcon(QIcon::fromTheme("list-remove")); + m_delete_action->setIcon(YIconManager::Get()->GetIcon(YIconManager::ListRemove)); m_new_action = new QAction("&New field", this); - m_new_action->setIcon(QIcon::fromTheme("list-add")); + m_new_action->setIcon(YIconManager::Get()->GetIcon(YIconManager::ListAdd)); setLayout(main_layout); @@ -1101,6 +1149,7 @@ RegEditPanel::RegEditPanel(const soc_desc::register_ref_t& ref, QWidget *parent) connect(m_sexy_display2, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(OnRegDisplayContextMenu(QPoint))); connect(m_reg_size_group, SIGNAL(buttonClicked(int)), this, SLOT(OnWidthChanged(int))); + connect(m_reg_access_group, SIGNAL(buttonClicked(int)), this, SLOT(OnAccessChanged(int))); connect(m_delete_action, SIGNAL(triggered()), this, SLOT(OnRegFieldDelete())); connect(m_new_action, SIGNAL(triggered()), this, SLOT(OnRegFieldNew())); connect(m_variant_table, SIGNAL(itemActivated(QTableWidgetItem *)), this, @@ -1110,6 +1159,7 @@ RegEditPanel::RegEditPanel(const soc_desc::register_ref_t& ref, QWidget *parent) connect(m_desc_edit, SIGNAL(OnTextChanged()), this, SLOT(OnDescEdited())); connect(m_fields_tab, SIGNAL(tabCloseRequested(int)), this, SLOT(OnFieldRemove(int))); connect(m_fields_tab, SIGNAL(tabOpenRequested()), this, SLOT(OnFieldCreate())); + connect(m_value_model, SIGNAL(OnBitrangeModified(int)), this, SLOT(OnBitrangeModified(int))); } void RegEditPanel::UpdateWidthRestrictions() @@ -1148,6 +1198,22 @@ void RegEditPanel::OnWidthChanged(int w) OnModified(); } +void RegEditPanel::OnBitrangeModified(int index) +{ + soc_desc::register_t reg = m_value_model->GetRegister(); + m_ref.get()->field[index].pos = reg.field[index].pos; + m_ref.get()->field[index].width = reg.field[index].width; + for(int i = 0; i < m_fields_tab->count(); i++) + dynamic_cast< RegFieldEditPanel * >(m_fields_tab->widget(i))->UpdateRange(); + OnModified(); +} + +void RegEditPanel::OnAccessChanged(int acc) +{ + m_ref.get()->access = (soc_desc::access_t)acc; + OnModified(); +} + void RegEditPanel::OnDescEdited() { m_ref.get()->desc = m_desc_edit->GetTextHtml().toStdString(); @@ -1169,9 +1235,11 @@ void RegEditPanel::OnVariantActivated(QTableWidgetItem *item) soc_desc::variant_t& variant = *m_ref.create_variant().get(); variant.type = "untyped"; variant.offset = 0; + variant.access = soc_desc::UNSPECIFIED; m_variant_table->insertRow(row); QTableWidgetItem *item = new QTableWidgetItem( - QIcon::fromTheme("list-remove"), "", RegVariantEditPanelDelType); + YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", RegVariantEditPanelDelType); + item->setToolTip("Remove this variant"); item->setFlags(Qt::ItemIsEnabled); m_variant_table->setItem(row, 0, item); item = new QTableWidgetItem(QString::fromStdString(variant.type)); @@ -1179,6 +1247,9 @@ void RegEditPanel::OnVariantActivated(QTableWidgetItem *item) item = new QTableWidgetItem(); item->setData(Qt::EditRole, QVariant(variant.offset)); m_variant_table->setItem(row, 2, item); + item = new QTableWidgetItem(); + item->setData(Qt::EditRole, QVariant::fromValue(variant.access)); + m_variant_table->setItem(row, 3, item); OnModified(); } } @@ -1193,6 +1264,8 @@ void RegEditPanel::OnVariantValueChanged(QTableWidgetItem *item) var.type = item->text().toStdString(); else if(item->column() == 2) var.offset = item->data(Qt::EditRole).value< soc_word_t >(); + else if(item->column() == 3) + var.access = item->data(Qt::EditRole).value< soc_desc::access_t >(); OnModified(); } @@ -1346,20 +1419,22 @@ RegEdit::RegEdit(Backend *backend, QWidget *parent) m_file_edit->setReadOnly(true); m_file_open = new QToolButton(this); m_file_open->setText("Open"); - m_file_open->setIcon(QIcon::fromTheme("document-open")); + m_file_open->setIcon(YIconManager::Get()->GetIcon(YIconManager::DocumentOpen)); m_file_open->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); QMenu *file_open_menu = new QMenu(this); - QAction *new_act = file_open_menu->addAction(QIcon::fromTheme("document-new"), "New..."); + QAction *new_act = file_open_menu->addAction(YIconManager::Get()->GetIcon(YIconManager::DocumentNew), + "New..."); m_file_open->setPopupMode(QToolButton::MenuButtonPopup); m_file_open->setMenu(file_open_menu); m_file_save = new QToolButton(this); m_file_save->setText("Save"); - m_file_save->setIcon(QIcon::fromTheme("document-save")); + m_file_save->setIcon(YIconManager::Get()->GetIcon(YIconManager::DocumentSave)); m_file_save->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); m_file_save->setPopupMode(QToolButton::MenuButtonPopup); QMenu *file_save_menu = new QMenu(this); - QAction *saveas_act = file_save_menu->addAction(QIcon::fromTheme("document-save-as"), "Save as..."); + QAction *saveas_act = file_save_menu->addAction(YIconManager::Get()->GetIcon(YIconManager::DocumentSaveAs), + "Save as..."); m_file_save->setMenu(file_save_menu); QHBoxLayout *file_group_layout = new QHBoxLayout(); @@ -1375,11 +1450,11 @@ RegEdit::RegEdit(Backend *backend, QWidget *parent) m_soc_tree->setContextMenuPolicy(Qt::CustomContextMenu); m_delete_action = new QAction("&Delete", this); - m_delete_action->setIcon(QIcon::fromTheme("list-remove")); + m_delete_action->setIcon(YIconManager::Get()->GetIcon(YIconManager::ListRemove)); m_new_action = new QAction("&New", this); - m_new_action->setIcon(QIcon::fromTheme("list-add")); + m_new_action->setIcon(YIconManager::Get()->GetIcon(YIconManager::ListAdd)); m_create_action = new QAction("&Create register", this); - m_create_action->setIcon(QIcon::fromTheme("folder-new")); + m_create_action->setIcon(YIconManager::Get()->GetIcon(YIconManager::FolderNew)); m_splitter->addWidget(m_soc_tree); m_splitter->setStretchFactor(0, 0); @@ -1605,8 +1680,8 @@ QIcon RegEdit::GetIconFromType(int type) { switch(type) { - case SocTreeSocType: return QIcon::fromTheme("computer"); - case SocTreeNodeType: return QIcon::fromTheme("cpu"); + case SocTreeSocType: return YIconManager::Get()->GetIcon(YIconManager::Computer); + case SocTreeNodeType: return YIconManager::Get()->GetIcon(YIconManager::Cpu); case SocTreeRegType: return style()->standardIcon(QStyle::SP_ArrowRight); default: return QIcon(); } @@ -1627,7 +1702,7 @@ void RegEdit::FixupItem(QTreeWidgetItem *item) UpdateName(item); if(!ValidateName(item->text(0))) { - item->setIcon(0, QIcon::fromTheme("dialog-error")); + item->setIcon(0, YIconManager::Get()->GetIcon(YIconManager::DialogError)); if(item->text(0).size() == 0) { MakeItalic(item, true); @@ -1688,6 +1763,7 @@ void RegEdit::OnSocItemCreate() return; soc_desc::register_t reg; reg.width = 32; + reg.access = soc_desc::UNSPECIFIED; soc_desc::node_ref_t node = SocTreeItemVal< soc_desc::node_ref_t >(current); node.get()->register_.push_back(reg); QTreeWidgetItem *reg_item = MakeSocTreeItem(SocTreeRegType, node.reg()); diff --git a/utils/regtools/qeditor/regedit.h b/utils/regtools/qeditor/regedit.h index 2540500f29..893ec73421 100644 --- a/utils/regtools/qeditor/regedit.h +++ b/utils/regtools/qeditor/regedit.h @@ -165,6 +165,7 @@ public: RegFieldEditPanel(const soc_desc::field_ref_t& ref, QWidget *parent = 0); soc_desc::field_ref_t GetField(); void UpdateWidth(); + void UpdateRange(); signals: void OnModified(); @@ -203,12 +204,14 @@ protected slots: void OnRegFieldDelete(); void OnRegFieldNew(); void OnWidthChanged(int size); + void OnAccessChanged(int access); void OnFieldModified(); void OnDescEdited(); void OnVariantActivated(QTableWidgetItem *item); void OnVariantValueChanged(QTableWidgetItem *item); void OnFieldRemove(int index); void OnFieldCreate(); + void OnBitrangeModified(int index); protected: void DoModify(); @@ -228,8 +231,10 @@ protected: QAction *m_delete_action; QPoint m_menu_point; SocFieldItemDelegate *m_variant_delegate; + SocAccessItemDelegate *m_access_delegate; SocFieldEditorCreator *m_variant_editor; QButtonGroup *m_reg_size_group; + QButtonGroup *m_reg_access_group; }; class RegEdit : public QWidget, public DocumentTab diff --git a/utils/regtools/qeditor/regtab.cpp b/utils/regtools/qeditor/regtab.cpp index 2653908d41..c6a1f41ee9 100644 --- a/utils/regtools/qeditor/regtab.cpp +++ b/utils/regtools/qeditor/regtab.cpp @@ -75,10 +75,11 @@ RegTab::RegTab(Backend *backend, QWidget *parent) QVBoxLayout *left_layout = new QVBoxLayout; left->setLayout(left_layout); - QGroupBox *top_group = new QGroupBox("SOC selection"); - QVBoxLayout *top_group_layout = new QVBoxLayout; + QGroupBox *top_group = new QGroupBox(""); + QHBoxLayout *top_group_layout = new QHBoxLayout; m_soc_selector = new QComboBox; - top_group_layout->addWidget(m_soc_selector); + top_group_layout->addWidget(new QLabel("SOC:")); + top_group_layout->addWidget(m_soc_selector, 1); top_group->setLayout(top_group_layout); m_reg_tree = new QTreeWidget(); @@ -96,7 +97,7 @@ RegTab::RegTab(Backend *backend, QWidget *parent) left_layout->addWidget(m_type_selector); m_right_panel = new QVBoxLayout; - QGroupBox *data_sel_group = new QGroupBox("Data selection"); + QGroupBox *data_sel_group = new QGroupBox(""); QHBoxLayout *data_sel_layout = new QHBoxLayout; m_backend_selector = new BackendSelector(m_backend, this); m_backend_selector->SetNothingMessage("Select a data source to analyse its content."); @@ -108,6 +109,7 @@ RegTab::RegTab(Backend *backend, QWidget *parent) m_data_sel_reload = new QPushButton(this); m_data_sel_reload->setIcon(QIcon::fromTheme("view-refresh")); m_data_sel_reload->setToolTip("Reload data"); + data_sel_layout->addWidget(new QLabel("Data:")); data_sel_layout->addWidget(m_backend_selector); data_sel_layout->addWidget(m_readonly_check); data_sel_layout->addWidget(m_data_soc_label); @@ -146,7 +148,9 @@ RegTab::RegTab(Backend *backend, QWidget *parent) connect(m_type_selector, SIGNAL(currentChanged(int)), this, SLOT(OnTypeChanged(int))); m_msg_select_id = SetMessage(MessageWidget::Information, - "You can browse the registers. Select a data source to analyse the values."); + "You can browse the registers using the left panel. " + "Select a data source at the top to analyse the values. " + "You can also use the analyzers available in the left panel, if any."); m_msg_error_id = 0; QList< SocFileRef > socs = m_backend->GetSocFileList(); @@ -215,8 +219,7 @@ void RegTab::UpdateTabName() else if(hwstub) { HWStubDevice *dev = hwstub->GetDevice(); - SetTabName(QString("HWStub %1.%2").arg(dev->GetBusNumber()) - .arg(dev->GetDevAddress())); + SetTabName(dev->GetFriendlyName()); } #endif else @@ -231,11 +234,21 @@ void RegTab::OnBackendSelect(IoBackend *backend) HideMessage(m_msg_select_id); HideMessage(m_msg_error_id); m_io_backend = backend; - SetReadOnlyIndicator(); - SetDataSocName(m_io_backend->GetSocName()); - OnDataSocActivated(m_io_backend->GetSocName()); - OnDataChanged(); - UpdateTabName(); + /* Check if the backend is valid, otherwise it might confuse the user */ + if(m_io_backend->IsValid()) + { + SetReadOnlyIndicator(); + SetDataSocName(m_io_backend->GetSocName()); + OnDataSocActivated(m_io_backend->GetSocName()); + OnDataChanged(); + UpdateTabName(); + } + /* But don't display it for the dummy backend either */ + else if(dynamic_cast< DummyIoBackend * >(m_io_backend) == 0) + { + m_msg_error_id = SetMessage(MessageWidget::Error, + "Data source is not available."); + } } void RegTab::SetReadOnlyIndicator() @@ -267,6 +280,7 @@ void RegTab::OnAnalyserClicked(QListWidgetItem *current) void RegTab::DisplayNode(const soc_desc::node_inst_t& ref) { + HideMessage(m_msg_select_id); if(ref.node().is_root()) SetPanel(new SocDisplayPanel(this, m_io_backend, ref.soc())); else if(ref.node().reg().valid()) 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 @@ #include #include #include +#include +#include +#include /** * SocBitRangeValidator @@ -406,6 +409,11 @@ bool SocFieldBitRange::operator<(const SocFieldBitRange& o) const return m_last_bit < o.m_last_bit; } +bool SocFieldBitRange::operator!=(const SocFieldBitRange& o) const +{ + return m_first_bit != o.m_first_bit || m_last_bit != o.m_last_bit; +} + /** * SocFieldCachedItemDelegate */ @@ -475,6 +483,53 @@ void SocFieldCachedEditor::setValue(SocFieldCachedValue val) setField(m_value.value()); } +/** + * SocAccessItemDelegate + */ +QString SocAccessItemDelegate::displayText(const QVariant& value, const QLocale& locale) const +{ + if(isUserType< soc_desc::access_t >(value)) + { + soc_desc::access_t acc = value.value< soc_desc::access_t >(); + switch(acc) + { + case soc_desc::UNSPECIFIED: return m_unspec_text; + case soc_desc::READ_ONLY: return "Read-Only"; + case soc_desc::READ_WRITE: return "Read-Write"; + case soc_desc::WRITE_ONLY: return "Write-Only"; + default: return ""; + } + } + else + return QStyledItemDelegate::displayText(value, locale); +} + +/** + * SocAccessEditor + */ +SocAccessEditor::SocAccessEditor(const QString& unspec_text, QWidget *parent) + :QComboBox(parent) +{ + addItem(unspec_text, QVariant::fromValue(soc_desc::UNSPECIFIED)); + addItem("Read-Only", QVariant::fromValue(soc_desc::READ_ONLY)); + addItem("Read-Write", QVariant::fromValue(soc_desc::READ_WRITE)); + addItem("Write-Only", QVariant::fromValue(soc_desc::WRITE_ONLY)); +} + +SocAccessEditor::~SocAccessEditor() +{ +} + +soc_desc::access_t SocAccessEditor::access() const +{ + return itemData(currentIndex()).value< soc_desc::access_t >(); +} + +void SocAccessEditor::setAccess(soc_desc::access_t acc) +{ + setCurrentIndex(findData(QVariant::fromValue(acc))); +} + /** * SocFieldEditorCreator */ @@ -493,6 +548,19 @@ void SocFieldEditorCreator::setWidth(int bitcount) m_field.width = bitcount; } +/** + * SocAccessEditorCreator + */ +QWidget *SocAccessEditorCreator::createWidget(QWidget *parent) const +{ + return new SocAccessEditor(m_unspec_text, parent); +} + +QByteArray SocAccessEditorCreator::valuePropertyName() const +{ + return QByteArray("access"); +} + /** * SocFieldCachedEditorCreator */ @@ -602,8 +670,22 @@ bool RegFieldTableModel::setData(const QModelIndex& idx, const QVariant& value, if(role != Qt::EditRole) return false; int section = idx.column(); + if(section == BitRangeColumn) + { + if(idx.row() < 0 || idx.row() >= rowCount()) + return false; + if(value.type() != QVariant::UserType && value.userType() == qMetaTypeId< SocFieldBitRange >()) + return false; + SocFieldBitRange bitrange = value.value< SocFieldBitRange >(); + m_reg.field[idx.row()].pos = bitrange.GetFirstBit(); + m_reg.field[idx.row()].width = bitrange.GetLastBit() - bitrange.GetFirstBit() + 1; + emit OnBitrangeModified(idx.row()); + } if(section < FirstValueColumn || section >= FirstValueColumn + m_value.size()) + { + qDebug() << "ignore setData to column " << section; return false; + } section -= FirstValueColumn; const SocFieldCachedValue& v = value.value< SocFieldCachedValue >(); if(!m_value[section].isValid()) @@ -622,7 +704,12 @@ Qt::ItemFlags RegFieldTableModel::flags(const QModelIndex& index) const Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; int section = index.column(); if(section < FirstValueColumn || section >= FirstValueColumn + m_value.size()) + { + /* bitrange or name */ + if(!m_read_only) + flags |= Qt::ItemIsEditable; return flags; + } section -= FirstValueColumn; if(m_value[section].isValid() && !m_read_only) flags |= Qt::ItemIsEditable; @@ -763,6 +850,207 @@ bool RegFieldProxyModel::lessThan(const QModelIndex& left, return QSortFilterProxyModel::lessThan(left, right); } +/** + * YRegDisplayItemEditor + */ +YRegDisplayItemEditor::YRegDisplayItemEditor(QWidget *parent, YRegDisplay *display, + YRegDisplayItemDelegate *delegate, QModelIndex bitrange_index, + QModelIndex name_index) + :QWidget(parent), m_display_delegate(delegate), + m_display(display), m_state(Idle) +{ + m_col_width = m_display->BitrangeRect(SocFieldBitRange(0, 0)).width(); + m_resize_margin = m_col_width / 4; + setEditorData(bitrange_index, name_index); + setMouseTracking(true); + setAutoFillBackground(true); + setFocusPolicy(Qt::StrongFocus); // QItemDelegate says it's important +} + +void YRegDisplayItemEditor::setEditorData(QModelIndex bitrange_index, QModelIndex name_index) +{ + if(m_state != Idle) + { + m_state = Idle; + QApplication::restoreOverrideCursor(); + } + m_bitrange_index = bitrange_index; + m_name_index = name_index; + m_bitrange = bitrange_index.data().value< SocFieldBitRange >(); +} + +void YRegDisplayItemEditor::getEditorData(QVariant& name, QVariant& bitrange) +{ + name = QVariant(); /* don't touch the name */ + bitrange = QVariant::fromValue(m_bitrange); +} + +YRegDisplayItemEditor::~YRegDisplayItemEditor() +{ + /* make sure to restore cursor if modified */ + if(m_state != Idle) + { + m_state = Idle; + QApplication::restoreOverrideCursor(); + } +} + +YRegDisplayItemEditor::Zone YRegDisplayItemEditor::GetZone(const QPoint& pt) +{ + if(!rect().contains(pt)) + return NoZone; + if(pt.x() >= 0 && pt.x() <= m_resize_margin) + return ResizeLeftZone; + if(pt.x() >= width() - m_resize_margin && pt.x() <= width()) + return ResizeRightZone; + return MoveZone; +} + +void YRegDisplayItemEditor::mouseMoveEvent(QMouseEvent *event) +{ + Zone zone = GetZone(event->pos()); + bool in_resize_zone = (zone == ResizeLeftZone || zone == ResizeRightZone); + /* resizing/moving has priority */ + if(m_state == ResizingLeft || m_state == ResizingRight || m_state == Moving) + { + SocFieldBitRange new_bitrange = m_bitrange; + if(m_state == Moving) + { + /* Compute new bitrange: we know the offset of the mouse relative to the + * left of the register: use that offset to compute the new position of + * the MSB bit. To make it more natural, add half of a column of margin + * so that the register does not move until half of a bit column displacement + * was made */ + int bit = m_display->bitColumnAt(mapTo(m_display, + event->pos() - QPoint(m_move_offset - m_col_width / 2, 0))); + new_bitrange.SetLastBit(bit); + int w = m_bitrange.GetLastBit() - m_bitrange.GetFirstBit(); + /* make sure range is valid */ + if(bit - w < 0) + return; + new_bitrange.SetFirstBit(bit - w); + } + else + { + /* Compute new bitrange. To make it more natural, add quarter of a column of margin + * so that the register does not resize until quarter of a bit column displacement + * was made */ + int bit = m_display->bitColumnAt(mapTo(m_display, event->pos() + + QPoint(m_col_width / 4, 0))); + if(m_state == ResizingLeft) + new_bitrange.SetLastBit(bit); + else + new_bitrange.SetFirstBit(bit); + /* make sure range is valid */ + if(new_bitrange.GetLastBit() < new_bitrange.GetFirstBit()) + return; + } + /* make sure range does not overlap with other fields */ + /* TODO */ + /* update current bitrange (display only) and resize widget */ + if(m_bitrange != new_bitrange) + { + m_bitrange = new_bitrange; + /* resize widget */ + QRect rect = m_display->BitrangeRect(m_bitrange); + rect.moveTopLeft(parentWidget()->mapFromGlobal(m_display->mapToGlobal(rect.topLeft()))); + setGeometry(rect); + } + } + /* any zone -> resize zone */ + else if(in_resize_zone) + { + /* don't do unnecessary changes */ + if(m_state != InResizeZone) + { + /* restore old cursor if needed */ + if(m_state != Idle) + QApplication::restoreOverrideCursor(); + m_state = InResizeZone; + QApplication::setOverrideCursor(QCursor(Qt::SizeHorCursor)); + } + } + /* any zone -> move zone */ + else if(zone == MoveZone) + { + /* don't do unnecessary changes */ + if(m_state != InMoveZone) + { + /* restore old cursor if needed */ + if(m_state != Idle) + QApplication::restoreOverrideCursor(); + m_state = InMoveZone; + QApplication::setOverrideCursor(QCursor(Qt::SizeAllCursor)); + } + } + /* any zone -> no zone */ + else if(zone == NoZone) + { + if(m_state != Idle) + { + m_state = Idle; + QApplication::restoreOverrideCursor(); + } + } +} + +void YRegDisplayItemEditor::leaveEvent(QEvent *event) +{ + Q_UNUSED(event); + if(m_state == InResizeZone) + { + m_state = Idle; + QApplication::restoreOverrideCursor(); + } +} + +void YRegDisplayItemEditor::mousePressEvent(QMouseEvent *event) +{ + /* just in case the mouseMove event was not done */ + mouseMoveEvent(event); + /* we need to track mouse outside of widget but Qt already grabs the mouse + * for us on mouse press in widget */ + if(m_state == InResizeZone) + { + if(GetZone(event->pos()) == ResizeLeftZone) + m_state = ResizingLeft; + else + m_state = ResizingRight; + } + else if(m_state == InMoveZone) + { + m_state = Moving; + /* store offset from the left, to keep relative position of the register + * with respect to the mouse */ + m_move_offset = event->pos().x(); + } +} + +void YRegDisplayItemEditor::mouseReleaseEvent(QMouseEvent *event) +{ + if(m_state == ResizingLeft || m_state == ResizingRight || m_state == Moving) + { + QApplication::restoreOverrideCursor(); + m_state = Idle; + /* update cursor */ + mouseMoveEvent(event); + } +} + +void YRegDisplayItemEditor::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); + QPainter painter(this); + /* reuse delegate code to paint */ + QStyleOptionViewItemV4 opt = m_display->viewOptions(); + opt.state |= QStyle::State_HasFocus | QStyle::State_Selected | QStyle::State_Active; + opt.displayAlignment = Qt::AlignHCenter | Qt::AlignVCenter; + opt.rect = rect(); + opt.showDecorationSelected = true; + m_display_delegate->initStyleOption(&opt, m_name_index); + m_display_delegate->MyPaint(&painter, opt); +} + /** * YRegDisplayItemDelegate */ @@ -772,14 +1060,9 @@ YRegDisplayItemDelegate::YRegDisplayItemDelegate(QObject *parent) { } - void YRegDisplayItemDelegate::paint(QPainter *painter, - const QStyleOptionViewItem& option, const QModelIndex& index) const +void YRegDisplayItemDelegate::MyPaint(QPainter *painter, const QStyleOptionViewItemV4& option) const { QStyleOptionViewItemV4 opt = option; - // default alignment is centered unless specified - opt.displayAlignment = Qt::AlignHCenter | Qt::AlignVCenter; - initStyleOption(&opt, index); - painter->save(); // draw everything rotated, requires careful manipulation of the // rects involved @@ -789,17 +1072,58 @@ YRegDisplayItemDelegate::YRegDisplayItemDelegate(QObject *parent) QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); painter->restore(); +} + +void YRegDisplayItemDelegate::paint(QPainter *painter, + const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + QStyleOptionViewItemV4 opt = option; + // default alignment is centered unless specified + opt.displayAlignment = Qt::AlignHCenter | Qt::AlignVCenter; + initStyleOption(&opt, index); + + MyPaint(painter, opt); } QSize YRegDisplayItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { + /* useless in our case, the view ignores this */ Q_UNUSED(option); Q_UNUSED(index); return QSize(); } +QWidget *YRegDisplayItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + Q_UNUSED(option); + Q_UNUSED(index); + YRegDisplay *display = dynamic_cast< YRegDisplay* >(parent->parent()); + Q_ASSERT(display != nullptr); + /* column 0 is name, column 1 is range */ + return new YRegDisplayItemEditor(parent, display, const_cast< YRegDisplayItemDelegate* >(this), + index.sibling(index.row(), 0), index.sibling(index.row(), 1)); +} + +void YRegDisplayItemDelegate::setEditorData(QWidget *editor, const QModelIndex& index) const +{ + dynamic_cast< YRegDisplayItemEditor* >(editor)->setEditorData( + index.sibling(index.row(), 0), index.sibling(index.row(), 1)); +} + +void YRegDisplayItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + QVariant name, bitrange; + dynamic_cast< YRegDisplayItemEditor* >(editor)->getEditorData(name, bitrange); + if(name.isValid()) + model->setData(index.sibling(index.row(), 1), name); + if(bitrange.isValid()) + model->setData(index.sibling(index.row(), 0), bitrange); +} + /** * YRegDisplay */ @@ -814,7 +1138,8 @@ YRegDisplay::YRegDisplay(QWidget *parent) // the frame around the register is ugly, disable it setFrameShape(QFrame::NoFrame); setSelectionMode(SingleSelection); - setItemDelegate(new YRegDisplayItemDelegate()); + setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked); + setItemDelegate(new YRegDisplayItemDelegate(this)); } void YRegDisplay::setWidth(int nr_bits) @@ -1055,6 +1380,11 @@ QRect YRegDisplay::itemRect(const QModelIndex& index) const return itemRect(range, index.column()); } +QRect YRegDisplay::BitrangeRect(const SocFieldBitRange& range) const +{ + return itemRect(range, m_data_col); +} + QRect YRegDisplay::itemRect(const SocFieldBitRange& range, int col) const { int top, bot; @@ -1276,17 +1606,17 @@ MyTextEditor::MyTextEditor(QWidget *parent) m_edit->setAutoFormatting(QTextEdit::AutoAll); m_bold_button = new QToolButton(this); - m_bold_button->setIcon(QIcon::fromTheme("format-text-bold")); + m_bold_button->setIcon(YIconManager::Get()->GetIcon(YIconManager::FormatTextBold)); m_bold_button->setText("bold"); m_bold_button->setCheckable(true); m_italic_button = new QToolButton(this); - m_italic_button->setIcon(QIcon::fromTheme("format-text-italic")); + m_italic_button->setIcon(YIconManager::Get()->GetIcon(YIconManager::FormatTextItalic)); m_italic_button->setText("italic"); m_italic_button->setCheckable(true); m_underline_button = new QToolButton(this); - m_underline_button->setIcon(QIcon::fromTheme("format-text-underline")); + m_underline_button->setIcon(YIconManager::Get()->GetIcon(YIconManager::FormatTextUnderline)); m_underline_button->setText("underline"); m_underline_button->setCheckable(true); @@ -1419,10 +1749,13 @@ BackendSelector::BackendSelector(Backend *backend, QWidget *parent) :QWidget(parent), m_backend(backend) { m_data_selector = new QComboBox(this); - m_data_selector->addItem(QIcon::fromTheme("text-x-generic"), "Nothing...", QVariant(DataSelNothing)); - m_data_selector->addItem(QIcon::fromTheme("document-open"), "File...", QVariant(DataSelFile)); + m_data_selector->addItem(YIconManager::Get()->GetIcon(YIconManager::TextGeneric), + "Nothing...", QVariant(DataSelNothing)); + m_data_selector->addItem(YIconManager::Get()->GetIcon(YIconManager::DocumentOpen), + "File...", QVariant(DataSelFile)); #ifdef HAVE_HWSTUB - m_data_selector->addItem(QIcon::fromTheme("multimedia-player"), "Device...", QVariant(DataSelDevice)); + m_data_selector->addItem(YIconManager::Get()->GetIcon(YIconManager::MultimediaPlayer), + "USB Device...", QVariant(DataSelDevice)); #endif m_data_sel_edit = new QLineEdit(this); m_data_sel_edit->setReadOnly(true); @@ -1435,7 +1768,18 @@ BackendSelector::BackendSelector(Backend *backend, QWidget *parent) data_sel_layout->addStretch(0); #ifdef HAVE_HWSTUB m_dev_selector = new QComboBox; + m_ctx_model = new HWStubContextModel; + m_ctx_model->EnableDummy(true, "Please select a device..."); + m_dev_selector->setModel(m_ctx_model); /* m_dev_selector will delete m_ctx_model */ + m_ctx_selector = new QComboBox; + m_ctx_manager = HWStubManager::Get(); + m_ctx_selector->setModel(m_ctx_manager); + m_ctx_manage_button = new QPushButton(); + m_ctx_manage_button->setIcon(YIconManager::Get()->GetIcon(YIconManager::Preferences)); + m_ctx_manage_button->setToolTip("Manage contexts"); data_sel_layout->addWidget(m_dev_selector, 1); + data_sel_layout->addWidget(m_ctx_selector); + data_sel_layout->addWidget(m_ctx_manage_button); #endif m_io_backend = m_backend->CreateDummyIoBackend(); @@ -1443,18 +1787,25 @@ BackendSelector::BackendSelector(Backend *backend, QWidget *parent) connect(m_data_selector, SIGNAL(activated(int)), this, SLOT(OnDataSelChanged(int))); #ifdef HAVE_HWSTUB - connect(m_dev_selector, SIGNAL(currentIndexChanged(int)), - this, SLOT(OnDevChanged(int))); - connect(&m_hwstub_helper, SIGNAL(OnDevListChanged(bool, struct libusb_device *)), - this, SLOT(OnDevListChanged2(bool, struct libusb_device *))); + connect(m_ctx_selector, SIGNAL(currentIndexChanged(int)), this, + SLOT(OnContextSelChanged(int))); + connect(m_dev_selector, SIGNAL(currentIndexChanged(int)), this, + SLOT(OnDeviceSelChanged(int))); + connect(m_dev_selector, SIGNAL(activated(int)), this, + SLOT(OnDeviceSelActivated(int))); +#endif + +#ifdef HAVE_HWSTUB + OnContextSelChanged(0); #endif OnDataSelChanged(0); } BackendSelector::~BackendSelector() { + /* avoid m_ctx_selector from deleting HWStubManager */ #ifdef HAVE_HWSTUB - ClearDevList(); + m_ctx_selector->setModel(new QStandardItemModel()); #endif delete m_io_backend; } @@ -1475,6 +1826,8 @@ void BackendSelector::OnDataSelChanged(int index) m_data_sel_edit->show(); #ifdef HAVE_HWSTUB m_dev_selector->hide(); + m_ctx_selector->hide(); + m_ctx_manage_button->hide(); #endif QFileDialog *fd = new QFileDialog(m_data_selector); QStringList filters; @@ -1496,7 +1849,10 @@ void BackendSelector::OnDataSelChanged(int index) m_nothing_text->hide(); m_data_sel_edit->hide(); m_dev_selector->show(); - OnDevListChanged(); + m_ctx_selector->show(); + m_ctx_manage_button->show(); + /* explicitely change the backend now */ + OnDeviceSelActivated(m_dev_selector->currentIndex()); } #endif else @@ -1505,59 +1861,14 @@ void BackendSelector::OnDataSelChanged(int index) m_nothing_text->show(); #ifdef HAVE_HWSTUB m_dev_selector->hide(); + m_ctx_selector->hide(); + m_ctx_manage_button->hide(); #endif ChangeBackend(m_backend->CreateDummyIoBackend()); } } -#ifdef HAVE_HWSTUB -void BackendSelector::OnDevListChanged2(bool arrived, struct libusb_device *dev) -{ - Q_UNUSED(arrived); - Q_UNUSED(dev); - OnDevListChanged(); -} - -void BackendSelector::OnDevListChanged() -{ - ClearDevList(); - QList< HWStubDevice* > list = m_hwstub_helper.GetDevList(); - foreach(HWStubDevice *dev, list) - { - QString name = QString("Bus %1 Device %2: %3").arg(dev->GetBusNumber()) - .arg(dev->GetDevAddress()).arg(dev->GetTargetInfo().bName); - m_dev_selector->addItem(QIcon::fromTheme("multimedia-player"), name, - QVariant::fromValue((void *)dev)); - } - if(list.size() > 0) - m_dev_selector->setCurrentIndex(0); -} - -void BackendSelector::OnDevChanged(int index) -{ - if(index == -1) - return; - HWStubDevice *dev = reinterpret_cast< HWStubDevice* >(m_dev_selector->itemData(index).value< void* >()); - delete m_io_backend; - /* NOTE: make a copy of the HWStubDevice device because the one in the list - * might get destroyed when clearing the list while the backend is still - * active: this would result in a double free when the backend is also destroyed */ - m_io_backend = m_backend->CreateHWStubIoBackend(new HWStubDevice(dev)); - emit OnSelect(m_io_backend); -} - -void BackendSelector::ClearDevList() -{ - while(m_dev_selector->count() > 0) - { - HWStubDevice *dev = reinterpret_cast< HWStubDevice* >(m_dev_selector->itemData(0).value< void* >()); - delete dev; - m_dev_selector->removeItem(0); - } -} -#endif - IoBackend *BackendSelector::GetBackend() { return m_io_backend; @@ -1572,16 +1883,46 @@ void BackendSelector::ChangeBackend(IoBackend *new_backend) m_io_backend = new_backend; } +#ifdef HAVE_HWSTUB +void BackendSelector::OnContextSelChanged(int index) +{ + m_ctx_model->SetContext(m_ctx_manager->GetContext(index)); + m_dev_selector->setCurrentIndex(0); +} + +void BackendSelector::OnDeviceSelChanged(int index) +{ + /* if current selection is -1, because device was removed or a new context + * was selected, select entry 0, which is dummy. Not that this will not + * call activate(), we don't want to change the current backend if the user + * is using another type of backend. */ + if(index == -1) + m_dev_selector->setCurrentIndex(0); +} + +void BackendSelector::OnDeviceSelActivated(int index) +{ + auto dev = new HWStubDevice(m_ctx_model->GetDevice(index)); + if(!dev->IsValid()) + { + delete dev; + ChangeBackend(m_backend->CreateDummyIoBackend()); + } + else + ChangeBackend(new HWStubIoBackend(dev)); +} +#endif + /** * YTabWidget */ YTabWidget::YTabWidget(QTabBar *bar, QWidget *parent) - :QTabWidget(parent) + :QTabWidget(parent), m_other_button(0) { if(bar != 0) setTabBar(bar); m_tab_open_button = new QToolButton(this); - m_tab_open_button->setIcon(QIcon::fromTheme("list-add")); + m_tab_open_button->setIcon(YIconManager::Get()->GetIcon(YIconManager::ListAdd)); m_tab_open_button->setAutoRaise(true); m_tab_open_button->setPopupMode(QToolButton::InstantPopup); /* the arrow with an icon only is pretty ugly and QToolButton has no way @@ -1592,8 +1933,8 @@ YTabWidget::YTabWidget(QTabBar *bar, QWidget *parent) connect(m_tab_open_button, SIGNAL(clicked(bool)), this, SLOT(OnOpenButton(bool))); /* there is a quirk in the default QStyle: if the tab bar is empty, it * returns the minimum size of the corner widget, which is 0 for tool buttons */ - //setMinimumHeight(m_tab_open_button->height()); - //m_tab_open_button->setMinimumHeight(m_tab_open_button->sizeHint().height()); + m_tab_open_button->setMinimumSize(m_tab_open_button->sizeHint()); + setMinimumSize(m_tab_open_button->sizeHint()); } void YTabWidget::setTabOpenable(bool openable) @@ -1613,6 +1954,28 @@ void YTabWidget::setTabOpenMenu(QMenu *menu) m_tab_open_button->setMenu(menu); } +void YTabWidget::setOtherMenu(QMenu *menu) +{ + if(menu == nullptr) + { + if(m_other_button) + delete m_other_button; + m_other_button = nullptr; + } + else + { + if(m_other_button == nullptr) + { + m_other_button = new QToolButton(this); + m_other_button->setText("Menu"); + m_other_button->setAutoRaise(true); + m_other_button->setPopupMode(QToolButton::InstantPopup); + setCornerWidget(m_other_button, Qt::TopRightCorner); + } + m_other_button->setMenu(menu); + } +} + /** * MessageWidget */ @@ -1625,6 +1988,7 @@ MessageWidget::MessageWidget(QWidget *parent) m_icon->hide(); m_text = new QLabel(this); m_text->setTextFormat(Qt::RichText); + m_text->setWordWrap(true); m_close = new QToolButton(this); m_close->setText("close"); m_close->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton)); @@ -1702,6 +2066,102 @@ void MessageWidget::OnClose(bool clicked) hide(); } +/* + * YIconManager + */ +YIconManager *YIconManager::m_singleton = nullptr; + +YIconManager::YIconManager() +{ + m_icon_name[ListAdd] = "list-add"; + m_icon_name[ListRemove] = "list-remove"; + m_icon_name[DocumentNew] = "document-new"; + m_icon_name[DocumentEdit] = "document-edit"; + m_icon_name[DocumentOpen] = "document-open"; + m_icon_name[DocumentSave] = "document-save"; + m_icon_name[DocumentSaveAs] = "document-save-as"; + m_icon_name[Preferences] = "preferences-system"; + m_icon_name[FolderNew] = "folder-new"; + m_icon_name[Computer] = "computer"; + m_icon_name[Cpu] = "cpu"; + m_icon_name[DialogError] = "dialog-error"; + m_icon_name[ViewRefresh] = "view-refresh"; + m_icon_name[SytemRun] = "system-run"; + m_icon_name[ApplicationExit] = "application-exit"; + m_icon_name[HelpAbout] = "help-about"; + m_icon_name[FormatTextBold] = "format-text-bold"; + m_icon_name[FormatTextItalic] = "format-text-italic"; + m_icon_name[FormatTextUnderline] = "format-text-underline"; + m_icon_name[TextGeneric] = "text-x-generic"; + m_icon_name[MultimediaPlayer] = "multimedia-player"; +} + +YIconManager::~YIconManager() +{ +} + +YIconManager *YIconManager::Get() +{ + if(m_singleton == nullptr) + m_singleton = new YIconManager(); + return m_singleton; +} + +QIcon YIconManager::GetIcon(IconType type) +{ + if(type < 0 || type >= MaxIcon) + return QIcon(); + if(QIcon::hasThemeIcon(m_icon_name[type])) + return QIcon::fromTheme(m_icon_name[type]); + /* render icon if needed */ + if(m_icon[type].isNull()) + Render(type); + return m_icon[type]; +} + +namespace +{ + void RenderListAdd(QIcon& icon) + { + QPixmap pix(64, 64); + pix.fill(Qt::transparent); + QPainter paint(&pix); + paint.fillRect(30, 12, 4, 40, QColor(255, 0, 0)); + paint.fillRect(12, 30, 40, 4, QColor(255, 0, 0)); + icon = QIcon(pix); + } + + void RenderListRemove(QIcon& icon) + { + QPixmap pix(64, 64); + pix.fill(Qt::transparent); + QPainter paint(&pix); + paint.setPen(QColor(255, 0, 0)); + paint.drawLine(12, 12, 52, 52); + paint.drawLine(12, 52, 52, 16); + icon = QIcon(pix); + } + + void RenderUnknown(QIcon& icon) + { + QPixmap pix(64, 64); + pix.fill(); + QPainter paint(&pix); + paint.fillRect(0, 0, 64, 64, QColor(255, 0, 0)); + icon = QIcon(pix); + } +} + +void YIconManager::Render(IconType type) +{ + switch(type) + { + case ListAdd: RenderListAdd(m_icon[type]); break; + case ListRemove: RenderListRemove(m_icon[type]); break; + default: RenderUnknown(m_icon[type]); break; + } +} + /** * Misc */ diff --git a/utils/regtools/qeditor/utils.h b/utils/regtools/qeditor/utils.h index 026466fae0..83992274b7 100644 --- a/utils/regtools/qeditor/utils.h +++ b/utils/regtools/qeditor/utils.h @@ -40,6 +40,7 @@ #include #include #include +#include #include "settings.h" #include "backend.h" @@ -180,6 +181,50 @@ protected: soc_desc::field_t m_field; }; +Q_DECLARE_METATYPE(soc_desc::access_t) + +class SocAccessItemDelegate: public QStyledItemDelegate +{ +public: + SocAccessItemDelegate(const QString& unspec_text, QObject *parent = 0) + :QStyledItemDelegate(parent), m_unspec_text(unspec_text) {} + + virtual QString displayText(const QVariant& value, const QLocale& locale) const; +protected: + QString m_unspec_text; +}; + +class SocAccessEditor : public QComboBox +{ + Q_OBJECT + Q_PROPERTY(soc_desc::access_t access READ access WRITE setAccess USER true) +public: + SocAccessEditor(const QString& unspec_text, QWidget *parent = 0); + virtual ~SocAccessEditor(); + + soc_desc::access_t access() const; + void setAccess(soc_desc::access_t acc); + +protected slots: + /* bla */ + +protected: + soc_desc::access_t m_access; +}; + +class SocAccessEditorCreator : public QItemEditorCreatorBase +{ +public: + SocAccessEditorCreator(const QString& unspec_text = "Unspecified") + :m_unspec_text(unspec_text) {} + + virtual QWidget *createWidget(QWidget *parent) const; + virtual QByteArray valuePropertyName() const; + +protected: + QString m_unspec_text; +}; + class SocFieldCachedValue { public: @@ -209,8 +254,11 @@ public: SocFieldBitRange(int first, int last):m_first_bit(first), m_last_bit(last) {} unsigned GetFirstBit() const { return m_first_bit; } unsigned GetLastBit() const { return m_last_bit; } + void SetFirstBit(unsigned bit) { m_first_bit = bit; } + void SetLastBit(unsigned bit) { m_last_bit = bit; } bool operator<(const SocFieldBitRange& o) const; + bool operator!=(const SocFieldBitRange& o) const; protected: unsigned m_first_bit, m_last_bit; }; @@ -301,6 +349,7 @@ public: signals: void OnValueModified(int index); + void OnBitrangeModified(int index); protected: void RecomputeTheme(); @@ -337,19 +386,79 @@ protected: bool lessThan(const QModelIndex& left, const QModelIndex& right) const; }; +class YRegDisplay; +class YRegDisplayItemDelegate; + +class YRegDisplayItemEditor : public QWidget +{ + Q_OBJECT +public: + YRegDisplayItemEditor(QWidget *parent, YRegDisplay *display, + YRegDisplayItemDelegate *delegate, QModelIndex bitrange_index, + QModelIndex name_index); + virtual ~YRegDisplayItemEditor(); + void setEditorData(QModelIndex bitrange_index, QModelIndex name_index); + void getEditorData(QVariant& name, QVariant& birange); + +protected: + virtual void paintEvent(QPaintEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void leaveEvent(QEvent *event); + + enum Zone + { + NoZone, + MoveZone, + ResizeLeftZone, + ResizeRightZone + }; + + Zone GetZone(const QPoint& pt); + + YRegDisplayItemDelegate *m_display_delegate; + YRegDisplay *m_display; + QModelIndex m_bitrange_index, m_name_index; + enum + { + Idle, + InResizeZone, + InMoveZone, + Moving, + ResizingLeft, + ResizingRight, + }m_state; + int m_col_width; + int m_resize_margin; + int m_move_offset; + SocFieldBitRange m_bitrange; +}; + class YRegDisplayItemDelegate : public QStyledItemDelegate { + Q_OBJECT + friend class YRegDisplayItemEditor; public: YRegDisplayItemDelegate(QObject *parent = 0); - virtual void paint(QPainter * painter, const QStyleOptionViewItem& option, - const QModelIndex & index) const; + virtual void paint(QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + virtual void MyPaint(QPainter *painter, const QStyleOptionViewItemV4& option) const; virtual QSize sizeHint(const QStyleOptionViewItem& option, - const QModelIndex & index) const; + const QModelIndex& index) const; + /* don't bother using the item factory and such, we only use this delegate + * for very specific models anyway */ + virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + virtual void setEditorData(QWidget *editor, const QModelIndex& index) const; + virtual void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const; }; class YRegDisplay : public QAbstractItemView { Q_OBJECT + friend class YRegDisplayItemEditor; public: YRegDisplay(QWidget *parent = 0); virtual QModelIndex indexAt(const QPoint& point) const; @@ -360,6 +469,8 @@ public: void setWidth(int nr_bits); /* returns the bit column at a point, or -1 if none except if closest=true */ int bitColumnAt(const QPoint& point, bool closest = true) const; + /* return rect for a bitrange */ + QRect BitrangeRect(const SocFieldBitRange& range) const; protected slots: virtual void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); @@ -509,18 +620,20 @@ protected: QLineEdit *m_data_sel_edit; #ifdef HAVE_HWSTUB QComboBox *m_dev_selector; - HWStubBackendHelper m_hwstub_helper; + QComboBox *m_ctx_selector; + QPushButton *m_ctx_manage_button; + HWStubContextModel *m_ctx_model; + HWStubManager *m_ctx_manager; #endif QLabel *m_nothing_text; private slots: -#ifdef HAVE_HWSTUB - void OnDevListChanged(); - void OnDevChanged(int index); - void OnDevListChanged2(bool, struct libusb_device *); - void ClearDevList(); -#endif void OnDataSelChanged(int index); +#ifdef HAVE_HWSTUB + void OnContextSelChanged(int index); + void OnDeviceSelChanged(int index); + void OnDeviceSelActivated(int index); +#endif }; class MessageWidget : public QFrame @@ -567,6 +680,7 @@ public: inline bool tabOpenable() const { return m_tab_openable; } void setTabOpenable(bool openable); void setTabOpenMenu(QMenu *menu); + void setOtherMenu(QMenu *menu); signals: void tabOpenRequested(); @@ -577,6 +691,52 @@ protected slots: protected: bool m_tab_openable; QToolButton *m_tab_open_button; + QToolButton *m_other_button; +}; + +class YIconManager : public QObject +{ + Q_OBJECT +protected: + YIconManager(); +public: + virtual ~YIconManager(); + /* list of icons */ + enum IconType + { + ListAdd = 0, + ListRemove, + DocumentNew, + DocumentEdit, + DocumentOpen, + DocumentSave, + DocumentSaveAs, + Preferences, + FolderNew, + Computer, + Cpu, + DialogError, + ViewRefresh, + SytemRun, + ApplicationExit, + HelpAbout, + FormatTextBold, + FormatTextItalic, + FormatTextUnderline, + TextGeneric, + MultimediaPlayer, + MaxIcon + }; + /* return instance */ + static YIconManager *Get(); + QIcon GetIcon(IconType it); + +protected: + void Render(IconType type); + + static YIconManager *m_singleton; // single instance + QIcon m_icon[MaxIcon]; /* list add icon */ + QString m_icon_name[MaxIcon]; /* icon name from theme */ }; class Misc