diff options
Diffstat (limited to 'src/libgui')
55 files changed, 8683 insertions, 0 deletions
diff --git a/src/libgui/Makefile.am b/src/libgui/Makefile.am new file mode 100644 index 0000000..b12fc23 --- /dev/null +++ b/src/libgui/Makefile.am @@ -0,0 +1,12 @@ +INCLUDES = -I$(top_srcdir)/src $(all_includes) +METASOURCES = AUTO + +noinst_LTLIBRARIES = libgui.la +libgui_la_LDFLAGS = $(all_libraries) +libgui_la_SOURCES = editor.cpp device_gui.cpp toplevel.cpp object_view.cpp \ + config_gen.cpp register_view.cpp device_editor.cpp watch_view.cpp project.cpp \ + project_editor.cpp project_manager.cpp hex_editor.cpp global_config.cpp config_center.cpp \ + editor_manager.cpp new_dialogs.cpp text_editor.cpp log_view.cpp gui_prog_manager.cpp \ + gui_debug_manager.cpp breakpoint_view.cpp likeback.cpp main_global.cpp console.cpp \ + project_wizard.cpp toplevel_ui.cpp project_manager_ui.cpp + diff --git a/src/libgui/breakpoint_view.cpp b/src/libgui/breakpoint_view.cpp new file mode 100644 index 0000000..6f49aac --- /dev/null +++ b/src/libgui/breakpoint_view.cpp @@ -0,0 +1,94 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "breakpoint_view.h" + +#include <qlayout.h> +#include <klocale.h> +#include <qpopupmenu.h> + +#include "main_global.h" +#include "editor_manager.h" +#include "coff/base/text_coff.h" +#include "gui_debug_manager.h" + +//---------------------------------------------------------------------------- +void Breakpoint::updateActions(const Data *data) +{ + bool hasBreakpoint = (data ? Breakpoint::list().contains(*data) : false); + Main::action("toggle_breakpoint")->setText(hasBreakpoint ? i18n("Remove breakpoint") : i18n("Set breakpoint")); + Main::action("toggle_breakpoint")->setEnabled(data); + bool isActive = (hasBreakpoint ? Breakpoint::list().state(*data)==Breakpoint::Active : false); + Main::action("enable_breakpoint")->setText(!isActive ? i18n("Enable breakpoint") : i18n("Disable breakpoint")); + Main::action("enable_breakpoint")->setEnabled(Debugger::manager->coff() && hasBreakpoint); +} + +//---------------------------------------------------------------------------- +Breakpoint::ListViewItem::ListViewItem(ListView *parent, const Data &data) + : KListViewItem(parent), _data(data) +{} + +//---------------------------------------------------------------------------- +Breakpoint::View::View(QWidget *parent) + : QWidget(parent, "breakpoints_view"), GenericView(Breakpoint::list()), + _currentData(0) +{ + QVBoxLayout *top = new QVBoxLayout(this); + _listview = new ListView(this); + connect(_listview, SIGNAL(clicked(QListViewItem *)), SLOT(itemClicked(QListViewItem *))); + connect(_listview, SIGNAL(contextMenuRequested(QListViewItem *, const QPoint &, int)), + SLOT(contextMenu(QListViewItem *, const QPoint &, int))); + _listview->setAllColumnsShowFocus(true); + _listview->addColumn(i18n("Status")); + _listview->addColumn(i18n("Location")); + _listview->addColumn(i18n("Address")); + top->addWidget(_listview); +} + +void Breakpoint::View::updateView() +{ + // #### flickering... + _listview->clear(); + for (uint i=0; i<Breakpoint::list().count(); i++) { + const Data &data = Breakpoint::list().data(i); + KListViewItem *item = new ListViewItem(_listview, data); + item->setPixmap(0, TextEditor::pixmap(Debugger::manager->breakpointType(data))); + item->setText(1, data.url.filename() + ":" + QString::number(data.line)); + Address address = Breakpoint::list().address(data); + if ( address.isValid() ) item->setText(2, toHexLabelAbs(address)); + else if ( Debugger::manager->coff() ) item->setText(2, i18n("Non-code breakpoint")); + else item->setText(2, "---"); + } +} + +void Breakpoint::View::itemClicked(QListViewItem *item) +{ + if ( item==0 ) return; + const Data &data = static_cast<ListViewItem *>(item)->data(); + Address address = Breakpoint::list().address(data); + TextEditor *editor = ::qt_cast<TextEditor *>(Main::currentEditor()); + const Coff::TextObject *coff = Debugger::manager->coff(); + int line = -1; + if ( coff && editor && editor->fileType()==PURL::Coff && address.isValid() ) + line = coff->lineForAddress(editor->url(), address); + if ( line==-1 ) { + editor = ::qt_cast<TextEditor *>(Main::editorManager().openEditor(data.url)); + line = data.line; + } + if ( editor==0 ) return; + editor->show(); + editor->setCursor(line, 0); +} + +void Breakpoint::View::contextMenu(QListViewItem *item, const QPoint &pos, int) +{ + _currentData = (item ? &static_cast<ListViewItem *>(item)->data() : 0); + updateActions(_currentData); + Main::popup("breakpoint_context_menu").exec(pos); + _currentData = 0; +} diff --git a/src/libgui/breakpoint_view.h b/src/libgui/breakpoint_view.h new file mode 100644 index 0000000..984a7ed --- /dev/null +++ b/src/libgui/breakpoint_view.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef BREAKPOINT_VIEW_H +#define BREAKPOINT_VIEW_H + +#include "progs/manager/breakpoint.h" +#include "common/gui/list_view.h" + +namespace Breakpoint +{ +//---------------------------------------------------------------------------- +class ListViewItem : public KListViewItem +{ +public: + ListViewItem(ListView *parent, const Data &data); + const Data &data() const { return _data; } + +private: + Data _data; +}; + +//---------------------------------------------------------------------------- +class View : public QWidget, public GenericView +{ +Q_OBJECT +public: + View(QWidget *parent); + virtual void updateView(); + const Data *currentData() const { return _currentData; } + +private slots: + void itemClicked(QListViewItem *item); + void contextMenu(QListViewItem *item, const QPoint &pos, int col); + +private: + ListView *_listview; + const Data *_currentData; +}; + +} // namespace + +#endif diff --git a/src/libgui/config_center.cpp b/src/libgui/config_center.cpp new file mode 100644 index 0000000..530cbbf --- /dev/null +++ b/src/libgui/config_center.cpp @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "config_center.h" + +#include <qlabel.h> +#include <qlayout.h> +#include <qtooltip.h> +#include <qgroupbox.h> +#include <qtabwidget.h> +#include <qtimer.h> +#include <kiconloader.h> +#include <klocale.h> +#include <klistview.h> + +#include "global_config.h" +#include "device_gui.h" +#include "tools/list/tools_config_widget.h" +#include "progs/gui/prog_config_center.h" +#include "progs/gui/debug_config_center.h" +#include "tools/list/compile_config.h" + +//---------------------------------------------------------------------------- +GlobalConfigWidget::GlobalConfigWidget() +{ + uint row = numRows(); + _showDebug = new KeyComboBox<Log::DebugLevel>(this); + FOR_EACH(Log::DebugLevel, level) _showDebug->appendItem(level, level.label()); + addWidget(_showDebug->widget(), row,row, 0,0); + row++; +} + +void GlobalConfigWidget::loadConfig() +{ + BaseGlobalConfigWidget::loadConfig(); + _showDebug->setCurrentItem(GlobalConfig::debugLevel()); +} + +void GlobalConfigWidget::saveConfig() +{ + BaseGlobalConfigWidget::saveConfig(); + GlobalConfig::writeDebugLevel(_showDebug->currentItem()); +} + +QPixmap GlobalConfigWidget::pixmap() const +{ + KIconLoader loader; + return loader.loadIcon("configure", KIcon::Toolbar, KIcon::SizeMedium); +} + +//---------------------------------------------------------------------------- +StandaloneConfigWidget::StandaloneConfigWidget() + : ConfigWidget(0) +{ + uint row = 0; + + QLabel *label = new QLabel(i18n("Device:"), this); + addWidget(label, row,row, 0,0); + _device = new DeviceChooser::Button(true, this); + addWidget(_device, row,row, 1,1); + row++; + + _tools = new ToolsConfigWidget(0, this); + addWidget(_tools, row,row, 0,2); + row++; + + setColStretch(2, 1); +} + +void StandaloneConfigWidget::loadConfig() +{ + _device->setDevice(Compile::Config::device(0)); + _tools->loadConfig(); +} + +void StandaloneConfigWidget::saveConfig() +{ + Compile::Config::setDevice(0, _device->device()); + _tools->saveConfig(); +} + +QPixmap StandaloneConfigWidget::pixmap() const +{ + KIconLoader loader; + return loader.loadIcon("configure", KIcon::Toolbar, KIcon::SizeMedium); +} + +//---------------------------------------------------------------------------- +ConfigWidget *ConfigCenter::factory(Type type) +{ + switch (type) { + case General: return new GlobalConfigWidget; + case ProgSelect: return new Programmer::SelectConfigWidget; + case ProgOptions: return new Programmer::OptionsConfigWidget; + case DebugOptions: return new Debugger::OptionsConfigWidget; + case Standalone: return new StandaloneConfigWidget; + case Nb_Types: break; + } + Q_ASSERT(false); + return 0; +} + +ConfigCenter::ConfigCenter(Type showType, QWidget *parent) + : Dialog(IconList, i18n("Configure Piklab"), Ok|Cancel, Cancel, parent, "configure_piklab_dialog", true, false) +{ + for (uint i=0; i<Nb_Types; i++) { + _configWidgets[i] = factory(Type(i)); + _configWidgets[i]->loadConfig(); + _pages[i] = addPage(_configWidgets[i]->title(), _configWidgets[i]->header(), _configWidgets[i]->pixmap()); + QVBoxLayout *vbox = new QVBoxLayout(_pages[i]); + _configWidgets[i]->reparent(_pages[i], QPoint(0,0)); + vbox->addWidget(_configWidgets[i]); + } + showPage(showType); +} + +void ConfigCenter::slotApply() +{ + for (uint i=0; i<Nb_Types; i++) _configWidgets[i]->saveConfig(); +} + +void ConfigCenter::slotOk() +{ + slotApply(); + accept(); +} diff --git a/src/libgui/config_center.h b/src/libgui/config_center.h new file mode 100644 index 0000000..1e543b7 --- /dev/null +++ b/src/libgui/config_center.h @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef CONFIG_CENTER_H +#define CONFIG_CENTER_H + +#include <qcheckbox.h> +#include <qlineedit.h> +#include <qwidgetstack.h> + +#include "common/gui/key_gui.h" +#include "common/gui/dialog.h" +#include "progs/gui/prog_config_widget.h" +#include "global_config.h" +namespace DeviceChooser { class Button; } +class SelectDirectoryWidget; +class ToolsConfigWidget; + +//---------------------------------------------------------------------------- +BEGIN_DECLARE_CONFIG_WIDGET(BaseGlobalConfig, BaseGlobalConfigWidget) +END_DECLARE_CONFIG_WIDGET + +class GlobalConfigWidget : public BaseGlobalConfigWidget +{ +Q_OBJECT +public: + GlobalConfigWidget(); + virtual QString title() const { return i18n("General"); } + virtual QString header() const { return i18n("General Configuration"); } + virtual QPixmap pixmap() const; + virtual void loadConfig(); + +public slots: + virtual void saveConfig(); + +private: + KeyComboBox<Log::DebugLevel> *_showDebug; +}; + +//---------------------------------------------------------------------------- +class StandaloneConfigWidget : public ConfigWidget +{ + Q_OBJECT +public: + StandaloneConfigWidget(); + virtual void loadConfig(); + virtual QString title() const { return i18n("Standalone File"); } + virtual QString header() const { return i18n("Standalone File Compilation"); } + virtual QPixmap pixmap() const; + +public slots: + virtual void saveConfig(); + +private: + DeviceChooser::Button *_device; + ToolsConfigWidget *_tools; +}; + +//---------------------------------------------------------------------------- +class ConfigCenter : public Dialog +{ +Q_OBJECT +public: + enum Type { General = 0, ProgSelect, ProgOptions, DebugOptions, + Standalone, Nb_Types }; + ConfigCenter(Type showType, QWidget *parent); + +public slots: + virtual void slotOk(); + virtual void slotApply(); + +private: + QWidget *_pages[Nb_Types]; + ConfigWidget *_configWidgets[Nb_Types]; + + static ConfigWidget *factory(Type type); +}; + +#endif diff --git a/src/libgui/config_gen.cpp b/src/libgui/config_gen.cpp new file mode 100644 index 0000000..036e62e --- /dev/null +++ b/src/libgui/config_gen.cpp @@ -0,0 +1,189 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "config_gen.h" + +#include <qlayout.h> +#include <qlabel.h> +#include <klocale.h> + +#include "device_gui.h" +#include "devices/base/generic_memory.h" +#include "devices/gui/hex_view.h" +#include "devices/gui/memory_editor.h" +#include "devices/base/device_group.h" +#include "devices/gui/device_group_ui.h" +#include "devices/list/device_list.h" +#include "text_editor.h" +#include "tools/list/tool_list.h" + +//----------------------------------------------------------------------------- +GeneratorDialog::GeneratorDialog(const QString &title, QWidget *parent, const char *name) + : Dialog(parent, name, true, title, Close|User1, Close, false, QSize(400, 300)) +{ + QVBoxLayout *top = new QVBoxLayout(mainWidget(), 10, 10); + + QHBoxLayout *hbox = new QHBoxLayout(top); + QLabel *label = new QLabel(i18n("Device:"), mainWidget()); + hbox->addWidget(label); + _deviceChooser = new DeviceChooser::Button(false, mainWidget()); + connect(_deviceChooser, SIGNAL(changed()), SLOT(reset())); + hbox->addWidget(_deviceChooser); + hbox->addSpacing(20); + + label = new QLabel(i18n("Toolchain:"), mainWidget()); + hbox->addWidget(label); + _configType = new KeyComboBox<QString>(mainWidget()); + Tool::Lister::ConstIterator it; + for (it=Tool::lister().begin(); it!=Tool::lister().end(); ++it) + _configType->appendItem(it.key(), it.data()->label()); + connect(_configType->widget(), SIGNAL(activated(int)), SLOT(typeChanged())); + hbox->addWidget(_configType->widget()); + + label = new QLabel(i18n("Tool Type:"), mainWidget()); + hbox->addWidget(label); + _toolType = new KeyComboBox<PURL::ToolType>(mainWidget()); + FOR_EACH(PURL::ToolType, type) _toolType->appendItem(type, type.label()); + _toolType->fixMinimumWidth(); + connect(_toolType->widget(), SIGNAL(activated(int)), SLOT(compute())); + hbox->addWidget(_toolType->widget()); + hbox->addStretch(1); + + _hbox = new QHBoxLayout(top); + + _text = new SimpleTextEditor(false, PURL::Nb_FileTypes, mainWidget()); + _text->setReadOnly(true); + top->addWidget(_text); + + _warning = new QLabel(mainWidget()); + top->addWidget(_warning); + + setButtonText(User1, i18n("Copy to clipboard")); +} + +void GeneratorDialog::set(const Device::Data *data, const Tool::Group &group, PURL::ToolType stype) +{ + QString device; + if ( data==0 ) { + QValueVector<QString> devices = group.supportedDevices(); + if ( devices.isEmpty() ) return; + device = devices[0]; + } else device = data->name(); + _deviceChooser->setDevice(device); + _configType->setCurrentItem(group.name()); + setToolType(stype); + reset(); +} + +void GeneratorDialog::typeChanged() +{ + setToolType(PURL::ToolType::Nb_Types); + compute(); +} + +void GeneratorDialog::setToolType(PURL::ToolType stype) +{ + const Tool::Group *group = Tool::lister().group(_configType->currentItem()); + _toolType->clear(); + FOR_EACH(PURL::ToolType, type) + if ( group->implementationType(type)!=PURL::Nb_FileTypes ) _toolType->appendItem(type, type.label()); + _toolType->setCurrentItem(stype); + _toolType->widget()->setEnabled( _toolType->count()>=2 ); +} + +PURL::ToolType GeneratorDialog::toolType() const +{ + return _toolType->currentItem(); +} + +void GeneratorDialog::compute() +{ + const Tool::Group *group = Tool::lister().group(_configType->currentItem()); + _warning->hide(); + if ( group->isSupported(_deviceChooser->device()) ) { + const Tool::SourceGenerator *generator = group->sourceGenerator(); + if ( generator==0 ) { + _text->setFileType(PURL::Nb_FileTypes); + _text->setText(i18n("Generation is not supported yet for the selected toolchain or device.")); + } else { + bool ok = true; + PURL::FileType type = group->implementationType(toolType()); + SourceLine::List lines = generateLines(ok); + if ( ok && lines.isEmpty() ) { + _text->setFileType(PURL::Nb_FileTypes); + _text->setText(i18n("This toolchain does not need explicit config bits.")); + } else { + _text->setFileType(type); + _text->setText(SourceLine::text(type.data().sourceFamily, lines, 4)); + } + if ( !ok ) { + _warning->show(); + _warning->setText(i18n("Generation is only partially supported for this device.")); + } + } + } else { + _text->setFileType(PURL::Nb_FileTypes); + if ( group->supportedDevices().isEmpty() ) _text->setText(i18n("Could not detect supported devices for selected toolchain. Please check installation.")); + else _text->setText(i18n("Device not supported by the selected toolchain.")); + } +} + +void GeneratorDialog::slotUser1() +{ + _text->selectAll(); + _text->copy(); + _text->deselect(); +} + +//----------------------------------------------------------------------------- +ConfigGenerator::ConfigGenerator(QWidget *parent) + : GeneratorDialog(i18n("Config Generator"), parent, "config_generator"), _memory(0), _configEditor(0) +{} + +ConfigGenerator::~ConfigGenerator() +{ + delete _memory; +} + +void ConfigGenerator::reset() +{ + delete _memory; + const Device::Data *data = Device::lister().data(_deviceChooser->device()); + _memory = data->group().createMemory(*data); + delete _configEditor; + _configEditor = Device::groupui(*data).createConfigEditor(*_memory, mainWidget()); + if (_configEditor) { + _configEditor->show(); + connect(_configEditor, SIGNAL(modified()), SLOT(compute())); + _configEditor->updateDisplay(); + _hbox->addWidget(_configEditor); + } + compute(); +} + +SourceLine::List ConfigGenerator::generateLines(bool &ok) const +{ + const Tool::Group *group = Tool::lister().group(_configType->currentItem()); + const Tool::SourceGenerator *generator = group->sourceGenerator(); + Q_ASSERT(generator); + return generator->configLines(toolType(), *_memory, ok); +} + +//----------------------------------------------------------------------------- +TemplateGenerator::TemplateGenerator(QWidget *parent) + : GeneratorDialog(i18n("Template Generator"), parent, "template_generator") +{} + +SourceLine::List TemplateGenerator::generateLines(bool &ok) const +{ + const Tool::Group *group = Tool::lister().group(_configType->currentItem()); + const Tool::SourceGenerator *generator = group->sourceGenerator(); + Q_ASSERT(generator); + const Device::Data *data = Device::lister().data(_deviceChooser->device()); + return generator->templateSourceFile(toolType(), *data, ok); +} diff --git a/src/libgui/config_gen.h b/src/libgui/config_gen.h new file mode 100644 index 0000000..fa9fd56 --- /dev/null +++ b/src/libgui/config_gen.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef CONFIG_GEN_H +#define CONFIG_GEN_H + +class QHBoxLayout; +class QLabel; + +#include "common/gui/dialog.h" +#include "tools/base/tool_group.h" +#include "common/gui/key_gui.h" +namespace DeviceChooser { class Button; } +namespace Device { + class Memory; + class MemoryEditor; +} +class SimpleTextEditor; + +//----------------------------------------------------------------------------- +class GeneratorDialog : public Dialog +{ +Q_OBJECT +public: + GeneratorDialog(const QString &title, QWidget *parent, const char *name); + void set(const Device::Data *data, const Tool::Group &group, PURL::ToolType stype); + +protected slots: + void typeChanged(); + virtual void reset() { compute(); } + virtual void compute(); + virtual void slotUser1(); + +protected: + QHBoxLayout *_hbox; + DeviceChooser::Button *_deviceChooser; + KeyComboBox<QString> *_configType; + KeyComboBox<PURL::ToolType> *_toolType; + SimpleTextEditor *_text; + QLabel *_warning; + + PURL::ToolType toolType() const; + void setToolType(PURL::ToolType stype); + virtual SourceLine::List generateLines(bool &ok) const = 0; +}; + +//----------------------------------------------------------------------------- +class ConfigGenerator : public GeneratorDialog +{ +Q_OBJECT +public: + ConfigGenerator(QWidget *parent); + virtual ~ConfigGenerator(); + +private slots: + virtual void reset(); + +private: + Device::Memory *_memory; + Device::MemoryEditor *_configEditor; + + void setToolType(PURL::ToolType stype); + virtual SourceLine::List generateLines(bool &ok) const; +}; + +//----------------------------------------------------------------------------- +class TemplateGenerator : public GeneratorDialog +{ +Q_OBJECT +public: + TemplateGenerator(QWidget *parent); + +private: + virtual SourceLine::List generateLines(bool &ok) const; +}; + +#endif diff --git a/src/libgui/console.cpp b/src/libgui/console.cpp new file mode 100644 index 0000000..99c996c --- /dev/null +++ b/src/libgui/console.cpp @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "console.h" + +#include <qlayout.h> +#include <qlabel.h> +#include <qdir.h> +#include <klibloader.h> +#include <klocale.h> +#include <kparts/part.h> +#include <kde_terminal_interface.h> + +ConsoleView::ConsoleView(QWidget *parent) + : QWidget(parent, "console_view"), _initialized(false) +{} + +void ConsoleView::showEvent(QShowEvent *e) +{ + if ( !_initialized ) { + _initialized = true; + KLibFactory *factory = KLibLoader::self()->factory("libkonsolepart"); + QVBoxLayout *top = new QVBoxLayout(this, 0, 10); + if ( factory==0 ) { + QLabel *label = new QLabel(i18n("Could not find \"konsolepart\"; please install kdebase."), this); + label->show(); + top->addWidget(label); + return; + } else { + QWidget *pwidget = static_cast<KParts::Part *>(factory->create(this, "konsole"))->widget(); + pwidget->show(); + top->addWidget(pwidget); + setFocusProxy(pwidget); + } + } + QWidget::showEvent(e); +} diff --git a/src/libgui/console.h b/src/libgui/console.h new file mode 100644 index 0000000..e073754 --- /dev/null +++ b/src/libgui/console.h @@ -0,0 +1,27 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef CONSOLE_H +#define CONSOLE_H + +#include <qwidget.h> + +class ConsoleView : public QWidget +{ +Q_OBJECT +public: + ConsoleView(QWidget *parent); + +protected: + virtual void showEvent(QShowEvent *e); + +private: + bool _initialized; +}; + +#endif diff --git a/src/libgui/device_editor.cpp b/src/libgui/device_editor.cpp new file mode 100644 index 0000000..7a2a3c6 --- /dev/null +++ b/src/libgui/device_editor.cpp @@ -0,0 +1,141 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "device_editor.h" + +#include <qscrollview.h> +#include <qregexp.h> + +#include "devices/list/device_list.h" +#include "toplevel.h" +#include "gui_debug_manager.h" +#include "project_manager.h" +#include "common/global/pfile.h" +#include "main_global.h" + +DeviceEditor::DeviceEditor(const QString &title, const QString &tag, QWidget *parent, const char *name) + : Editor(title, tag, parent, name), _view(0) +{ + init(); +} + +DeviceEditor::DeviceEditor(QWidget *parent, const char *name) + : Editor(parent, name), _view(0) +{ + init(); +} + +void DeviceEditor::init() +{ + QHBoxLayout *hbox = new QHBoxLayout(this, 0); + QScrollView *sview = new QScrollView(this, "scroll_view"); + sview->setResizePolicy(QScrollView::AutoOneFit); + hbox->addWidget(sview); + _widget = new QWidget(sview->viewport(), "main_scroll_widget"); + sview->addChild(_widget); + _top = new QVBoxLayout(_widget, 0, 0); + _labelDevice = new QLabel(_widget); + _labelDevice->setMargin(10); + _labelDevice->setTextFormat(RichText); + _top->addWidget(_labelDevice); + _labelWarning = new QLabel(_widget); + _labelWarning->setMargin(10); + _labelWarning->setTextFormat(RichText); + _top->addWidget(_labelWarning); + _vbox = new QVBoxLayout(_top); + + connect(&Main::toplevel(), SIGNAL(stateChanged()), SLOT(updateDevice())); +} + +void DeviceEditor::setDevice(bool force) +{ + if ( Main::device()==Device::AUTO_DATA.name ) { + PURL::Url url = Main::projectManager().projectUrl(); + QString name = guessDeviceFromFile(url); + if ( !force && name==_device ) return; + _device = name; + if ( name==Device::AUTO_DATA.name ) + _labelDevice->setText(i18n("The target device is not configured and cannot be guessed from source file. " + "The source file either cannot be found or does not contain any processor directive.")); + else _labelDevice->setText(i18n("Device guessed from file: %1").arg(name)); + _labelDevice->show(); + } else { + if ( !force && Main::device()==_device ) return; + _device = Main::device(); + _labelDevice->hide(); + } + if ( _view && isModified() ) { + if ( MessageBox::questionYesNo(i18n("File %1 not saved.").arg(filename()), KStdGuiItem::save(), KStdGuiItem::discard()) ) + Editor::save(); + } + _labelWarning->hide(); + const Device::Data *data = Device::lister().data(_device); + delete _view; + _view = createView(data, _widget); + if (_view) { + _view->show(); + _vbox->addWidget(_view); + updateGeometry(); + } + setModified(false); + emit guiChanged(); +} + +PURL::Url DeviceEditor::findAsmFile(const PURL::Url &url) +{ + if ( url.isEmpty() ) return PURL::Url(); + PURL::SourceFamily family = url.fileType().data().sourceFamily; + if ( family.data().toolType==PURL::ToolType::Assembler ) return url; + FOR_EACH(PURL::FileType, i) { + PURL::SourceFamily source = i.data().sourceFamily; + if ( source.data().toolType!=PURL::ToolType::Assembler ) continue; + for (uint k=0; i.data().extensions[k]; k++) { + PURL::Url src = url.toExtension(i.data().extensions[k]); + if ( PURL::findExistingUrl(src) ) return src; + } + } + return PURL::Url(); +} + +QString DeviceEditor::guessDeviceFromFile(const PURL::Url &url) +{ + PURL::Url src = findAsmFile(url); + if ( src.isEmpty() ) return Device::AUTO_DATA.name; + Log::StringView sview; + PURL::File file(src, sview); + if ( !file.openForRead() ) return Device::AUTO_DATA.name; + + QString device; + // QRegExp re1("^[ \\t]+(?:PROCESSOR|processor)[ \\t]+((?:p|sx|P|SX)[a-z0-9A-Z]+)" ) ; + QRegExp re1("^[ \\t]+(?:PROCESSOR|processor)[ \\t]+([a-z0-9A-Z]+)" ) ; + QRegExp re2("^[ \\t]+(?:LIST|list)[ \\t]+" ) ; + for (;;) { + QString line = file.readLine(); + if ( line.isNull() ) break; + // search PROCESSOR directive + if ( re1.search(line, 0)!=-1 ) { + device = re1.cap(1); + break; + } + // search LIST p=... directive + int k = re2.search(line,0); + if ( k!=-1 ) { + //QRegExp re3("(?:p|P)[ \\t]*=[ \\t]*((?:p|sx|P|SX)[a-z0-9A-Z]+)") ; + QRegExp re3("(?:p|P)[ \\t]*=[ \\t]*([a-z0-9A-Z]+)") ; + if ( re3.search(line, k+5)!=-1 ) { + device = re3.cap(1); + break; + } + } + } + device = device.upper(); + if( device[0]=='P') return device.mid(1); + if ( Device::lister().data(device)==0 ) return Device::AUTO_DATA.name; + return device; +} diff --git a/src/libgui/device_editor.h b/src/libgui/device_editor.h new file mode 100644 index 0000000..8b7cab7 --- /dev/null +++ b/src/libgui/device_editor.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef DEVICE_EDITOR_H +#define DEVICE_EDITOR_H + +#include "editor.h" +namespace Device { class Data; } + +class DeviceEditor : public Editor +{ +Q_OBJECT +public: + DeviceEditor(const QString &title, const QString &tag, QWidget *parent, const char *name); + DeviceEditor(QWidget *parent, const char *name); + virtual PURL::FileType fileType() const { return PURL::Nb_FileTypes; } + virtual PURL::Url url() const { return PURL::Url(); } + virtual void setDevice(bool force = false); + static QString guessDeviceFromFile(const PURL::Url &url); + virtual bool save(const PURL::Url &) { return false; } + virtual bool open(const PURL::Url &) { return true; } + virtual QValueList<uint> bookmarkLines() const { return QValueList<uint>(); } + virtual void setBookmarkLines(const QValueList<uint> &) {} + +public slots: + virtual void statusChanged() { emit statusTextChanged(" "); } + +protected: + QString _device; + QWidget *_widget, *_view; + QVBoxLayout *_top, *_vbox; + QLabel *_labelDevice, *_labelWarning; + + void init(); + virtual QWidget *createView(const Device::Data *data, QWidget *parent) = 0; + static PURL::Url findAsmFile(const PURL::Url &url); + +private slots: + void updateDevice() { setDevice(); } +}; + +#endif diff --git a/src/libgui/device_gui.cpp b/src/libgui/device_gui.cpp new file mode 100644 index 0000000..8183725 --- /dev/null +++ b/src/libgui/device_gui.cpp @@ -0,0 +1,463 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "device_gui.h" + +#include <qlayout.h> +#include <qpainter.h> +#include <qcombobox.h> +#include <qlabel.h> +#include <qcheckbox.h> +#include <qsplitter.h> +#include <kiconloader.h> +#include <kpushbutton.h> +#include <klistview.h> +#include <klocale.h> + +#include "devices/list/device_list.h" +#include "devices/base/device_group.h" +#include "devices/gui/device_group_ui.h" +#include "progs/list/prog_list.h" +#include "tools/list/device_info.h" +#include "tools/list/tool_list.h" + +namespace DeviceChooser +{ +//----------------------------------------------------------------------------- +void DeviceChooser::Config::writeProgrammerGroup(const Programmer::Group *group) +{ + writeEntry("programmer", group ? group->name() : QString::null); +} +const Programmer::Group *DeviceChooser::Config::programmerGroup() +{ + QString name = readEntry("programmer", QString::null); + return Programmer::lister().group(name); +} + +void DeviceChooser::Config::writeToolGroup(const Tool::Group *group) +{ + writeEntry("tool", group ? group->name() : QString::null); +} +const Tool::Group *DeviceChooser::Config::toolGroup() +{ + QString name = readEntry("tool", QString::null); + return Tool::lister().group(name); +} + +//----------------------------------------------------------------------------- +class ListItem : public KListViewItem +{ +public: + ListItem(KListView *list, const QString &name, bool selectable, bool isDevice) + : KListViewItem(list, name), _device(isDevice) { + setSelectable(selectable); + } + ListItem(KListViewItem *item, const QString &name) + : KListViewItem(item, name), _device(true) {} + + bool isDevice() const { return _device; } + virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align) { + QColorGroup ncg = cg; + if (_device) { + const Device::Data *device = Device::lister().data(text(0)); + Q_ASSERT(device); + ncg.setColor(QColorGroup::Text, Device::statusColor(device->status())); + } + KListViewItem::paintCell(p, ncg, column, width, align); + } + +private: + bool _device; +}; + +} // namespace + +//----------------------------------------------------------------------------- +const DeviceChooser::ListType::Data DeviceChooser::ListType::DATA[Nb_Types] = { + { "family_tree", I18N_NOOP("Family Tree") }, + { "flat", I18N_NOOP("Flat List") } +}; + +DeviceChooser::Dialog::Dialog(const QString &device, Type type, QWidget *parent) + : ::Dialog(parent, "device_chooser_dialog", true, i18n("Select a device"), + Ok|Close, Close, false, QSize(400, 300)), _withAuto(type==ChooseWithAuto) +{ + setButtonOK(KGuiItem(i18n( "&Select"), "button_ok")); + QVBoxLayout *top = new QVBoxLayout(mainWidget(), 0, 10); + + // view + QHBoxLayout *hbox = new QHBoxLayout(top, 10); + QVBoxLayout *vbox = new QVBoxLayout(hbox); + _listTypeCombo = new EnumComboBox<ListType>("list_type", mainWidget()); + connect(_listTypeCombo->combo(), SIGNAL(activated(int)), SLOT(updateList())); + vbox->addWidget(_listTypeCombo->combo()); + QPushButton *button = new KPushButton(KGuiItem(i18n("Reset Filters"), "reload"), mainWidget()); + connect(button, SIGNAL(clicked()), SLOT(resetFilters())); + vbox->addWidget(button); + vbox->addStretch(1); + + // filters + QFrame *frame = new QFrame(mainWidget()); + frame->setFrameStyle(QFrame::Panel | QFrame::Raised); + frame->setMargin(5); + hbox->addWidget(frame); + hbox = new QHBoxLayout(frame, 10, 10); + QLabel *label = new QLabel(i18n("Filters:"), frame); + hbox->addWidget(label); + vbox = new QVBoxLayout(hbox); + + QHBoxLayout *shbox = new QHBoxLayout(vbox); + + // programmer filter + _programmerCombo = new KeyComboBox<QString>(frame); + _programmerCombo->appendItem("<all>", i18n("<Programmer>")); + Programmer::Lister::ConstIterator pit; + for (pit=Programmer::lister().begin(); pit!=Programmer::lister().end(); ++pit) + _programmerCombo->appendItem(pit.key(), pit.data()->label()); + Config config; + const Programmer::Group *pgroup = config.programmerGroup(); + if (pgroup) _programmerCombo->setCurrentItem(pgroup->name()); + connect(_programmerCombo->widget(), SIGNAL(activated(int)), SLOT(updateList())); + shbox->addWidget(_programmerCombo->widget()); + + // tool filter + _toolCombo = new KeyComboBox<QString>(frame); + _toolCombo->appendItem("<all>", i18n("<Toolchain>")); + Tool::Lister::ConstIterator tit; + for (tit=Tool::lister().begin(); tit!=Tool::lister().end(); ++tit) { + if ( tit.data()->isCustom() ) continue; + _toolCombo->appendItem(tit.key(), tit.data()->label()); + } + const Tool::Group *tgroup = config.toolGroup(); + if (tgroup) _toolCombo->setCurrentItem(tgroup->name()); + connect(_toolCombo->widget(), SIGNAL(activated(int)), SLOT(updateList())); + shbox->addWidget(_toolCombo->widget()); + + // memory filter + _memoryCombo = new EnumComboBox<Device::MemoryTechnology>(i18n("<Memory Type>"), "memory_technology", frame); + connect(_memoryCombo->combo(), SIGNAL(activated(int)), SLOT(updateList())); + shbox->addWidget(_memoryCombo->combo()); + + shbox->addStretch(1); + shbox = new QHBoxLayout(vbox); + + // status filter + _statusCombo = new EnumComboBox<Device::Status>(i18n("<Status>"), "status", frame); + connect(_statusCombo->combo(), SIGNAL(activated(int)), SLOT(updateList())); + shbox->addWidget(_statusCombo->combo()); + + // features filter + _featureCombo = new EnumComboBox<Pic::Feature>(i18n("<Feature>"), "feature", frame); + connect(_featureCombo->combo(), SIGNAL(activated(int)), SLOT(updateList())); + shbox->addWidget(_featureCombo->combo()); + + shbox->addStretch(1); + + // list view + QValueList<int> widths; + widths += 80; + widths += 500; + Splitter *splitter = new Splitter(widths, Horizontal, mainWidget(), "device_shooser_splitter"); + top->addWidget(splitter, 1); + _listView = new KListView(splitter); + connect(_listView, SIGNAL(currentChanged(QListViewItem *)), + SLOT(currentChanged(QListViewItem *))); + connect(_listView, SIGNAL(doubleClicked(QListViewItem *, const QPoint &, int)), + SLOT(listDoubleClicked(QListViewItem *))); + _listView->setAllColumnsShowFocus(true); + _listView->setRootIsDecorated(true); + _listView->setSorting(-1); + _listView->addColumn(i18n("Device")); + _listView->setResizeMode(QListView::LastColumn); + + // device view + _deviceView = new View(splitter); + connect(_deviceView, SIGNAL(deviceChanged(const QString &)), + SLOT(deviceChange(const QString &))); + + updateList(device); +} + +DeviceChooser::Dialog::~Dialog() +{ + Config config; + config.writeProgrammerGroup(programmerGroup()); + config.writeToolGroup(toolGroup()); + _listTypeCombo->writeConfig(); + _memoryCombo->writeConfig(); + _statusCombo->writeConfig(); + _featureCombo->writeConfig(); +} + +QString DeviceChooser::Dialog::device() const +{ + QListViewItem *item = _listView->selectedItem(); + if ( item==0 || !static_cast<ListItem *>(item)->isDevice() ) return Device::AUTO_DATA.name; + return item->text(0); +} + +void DeviceChooser::Dialog::listDoubleClicked(QListViewItem *item) +{ + if ( item==0 ) return; + if ( !static_cast<ListItem *>(item)->isDevice() ) item->setOpen(!item->isOpen()); + else accept(); +} + +void DeviceChooser::Dialog::currentChanged(QListViewItem *item) +{ + if ( item==0 || !static_cast<ListItem *>(item)->isDevice() ) _deviceView->clear(); + else _deviceView->setDevice(item->text(0), false); +} + +void DeviceChooser::Dialog::deviceChange(const QString &name) +{ + QListViewItemIterator it(_listView); + for (; it.current(); ++it) + if ( it.current()->text(0)==name ) { + _listView->setSelected(it.current(), true); + _listView->ensureItemVisible(it.current()); + break; + } +} + +void DeviceChooser::Dialog::resetFilters() +{ + _programmerCombo->setCurrentItem("<all>"); + _toolCombo->setCurrentItem("<all>"); + _memoryCombo->reset(); + _statusCombo->reset(); + _featureCombo->reset(); + updateList(); +} + +void DeviceChooser::Dialog::updateList() +{ + QListViewItem *item = _listView->selectedItem(); + QString device = (item ? item->text(0) : QString::null); + _listView->clear(); + updateList(device); +} + +const Programmer::Group *DeviceChooser::Dialog::programmerGroup() const +{ + return Programmer::lister().group(_programmerCombo->currentItem()); +} + +const Tool::Group *DeviceChooser::Dialog::toolGroup() const +{ + return Tool::lister().group(_toolCombo->currentItem()); +} + +void DeviceChooser::Dialog::updateList(const QString &device) +{ + QValueVector<QString> list = Device::lister().supportedDevices(); + QMap<QString, KListViewItem *> groups; + QListViewItem *selected = 0; + const Programmer::Group *pgroup = programmerGroup(); + if ( pgroup && pgroup->supportedDevices().isEmpty() && pgroup->isSoftware() ) { + _deviceView->setText(i18n("Could not detect supported devices for \"%1\". Please check installation.").arg(pgroup->label())); + return; + } + const Tool::Group *tgroup = toolGroup(); + if ( tgroup && tgroup->supportedDevices().isEmpty() ) { + _deviceView->setText(i18n("Could not detect supported devices for toolchain \"%1\". Please check installation.").arg(tgroup->label())); + return; + } + for (int i=list.count()-1; i>=0; i--) { + if ( pgroup && !pgroup->isSupported(list[i]) ) continue; + if ( tgroup && !tgroup->isSupported(list[i]) ) continue; + const Device::Data *data = Device::lister().data(list[i]); + Q_ASSERT(data); + if ( _memoryCombo->value()!=Device::MemoryTechnology::Nb_Types && data->memoryTechnology()!=_memoryCombo->value() ) continue; + if ( _statusCombo->value()!=Device::Status::Nb_Types && data->status()!=_statusCombo->value() ) continue; + if ( _featureCombo->value()!=Pic::Feature::Nb_Types ) { + if ( data->group().name()!="pic" ) continue; + if ( !static_cast<const Pic::Data *>(data)->hasFeature(_featureCombo->value()) ) continue; + } + KListViewItem *item = 0; + switch (_listTypeCombo->value().type()) { + case ListType::FamilyTree: { + QString gname = data->listViewGroup(); + if ( !groups.contains(gname) ) + groups[gname] = new ListItem(_listView, gname, false, false); + item = new ListItem(groups[gname], list[i]); + break; + } + case ListType::Flat: + item = new ListItem(_listView, list[i], true, true); + break; + case ListType::Nb_Types: Q_ASSERT(false); break; + } + if ( device==list[i] ) selected = item; + } + if (_withAuto) (void)new ListItem(_listView, i18n(Device::AUTO_DATA.label), true, false); + if ( selected==0 ) selected = _listView->firstChild(); + if (selected) { + _listView->setSelected(selected, true); + _listView->ensureItemVisible(selected); + currentChanged(selected); + } +} + +//----------------------------------------------------------------------------- +DeviceChooser::ComboBox::ComboBox(bool withAuto, QWidget *parent) + : QComboBox(parent, "device_chooser_combo"), _withAuto(withAuto) +{ + if (withAuto) insertItem(i18n(Device::AUTO_DATA.label)); + Device::Lister::ConstIterator it; + for (it=Device::lister().begin(); it!=Device::lister().end(); ++it) { + QValueVector<QString> devices = it.data()->supportedDevices(); + qHeapSort(devices); + for (uint k=0; k<devices.count(); k++) insertItem(devices[k]); + } +} + +void DeviceChooser::ComboBox::setDevice(const QString &device, const Device::Data *data) +{ + QString text = device; + if ( device.isEmpty() || device==Device::AUTO_DATA.name ) { + if (_withAuto) text = QString::null; + else text = Device::lister().supportedDevices()[0]; + } + if ( text.isEmpty() ) { + if (data) changeItem(data->name() + " " + i18n(Device::AUTO_DATA.label), 0); + else changeItem(i18n(Device::AUTO_DATA.label), 0); + setCurrentItem(0); + } else setCurrentText(text); +} + +QString DeviceChooser::ComboBox::device() const +{ + if ( _withAuto && currentItem()==0 ) return Device::AUTO_DATA.name; + return currentText(); +} + +//----------------------------------------------------------------------------- +DeviceChooser::Button::Button(bool withAuto, QWidget *parent) + : QWidget(parent, "device_chooser_button") +{ + QHBoxLayout *hbox = new QHBoxLayout(this, 0, 10); + _combo = new ComboBox(withAuto, this); + connect(_combo, SIGNAL(activated(int)), SIGNAL(changed())); + hbox->addWidget(_combo); + KIconLoader loader; + QIconSet iconset = loader.loadIcon("fileopen", KIcon::Toolbar); + KPushButton *button = new KPushButton(iconset, QString::null, this); + connect(button, SIGNAL(clicked()), SLOT(chooseDevice())); + hbox->addWidget(button); +} + +void DeviceChooser::Button::chooseDevice() +{ + Dialog dialog(_combo->device(), (_combo->withAuto() ? ChooseWithAuto : Choose), this); + if ( !dialog.exec() || dialog.device().isEmpty() ) return; + _combo->setDevice(dialog.device()); + emit changed(); +} + +//----------------------------------------------------------------------------- +DeviceChooser::Browser::Browser(QWidget *parent) + : KTextBrowser(parent, "device_browser") +{} + +PURL::Url findDocumentUrl(const QString &prefix, const QString &baseName) +{ + PURL::Url previous = KURL::fromPathOrURL(prefix + baseName + ".pdf"); + bool previousExists = previous.exists(); + for (uint i=0; i<26; i++) { + PURL::Url url = KURL::fromPathOrURL(prefix + baseName + QChar('a' + i) + ".pdf"); + bool exists = url.exists(); + if ( !exists && previousExists ) return previous; + previous = url; + previousExists = exists; + } + return previous; +} + +void DeviceChooser::Browser::setSource(const QString &name) +{ + ::BusyCursor bc; + if ( name.startsWith("device://") ) emit deviceChanged(name.mid(9)); + else if ( name.startsWith("document://") ) { + QString prefix = "http://ww1.microchip.com/downloads/en/DeviceDoc/"; + PURL::Url url = findDocumentUrl(prefix, name.mid(11, name.length()-11-1)); + KTextBrowser::setSource(url.kurl().htmlURL()); + } + else KTextBrowser::setSource(name); +} + +//----------------------------------------------------------------------------- +DeviceChooser::View::View(QWidget *parent) + : TabWidget(parent, "device_view") +{ + // Information + _info = new Browser(this); + _info->setMimeSourceFactory(&_msf); + insertTab(_info, i18n("Information")); + connect(_info, SIGNAL(deviceChanged(const QString &)), + SIGNAL(deviceChanged(const QString &))); + + // Memory Map + _memory = new Browser(this); + _memory->setMimeSourceFactory(&_msf); + insertTab(_memory, i18n("Memory Map")); + + // Voltage-Frequency Graphs + _vfg = new Browser(this); + _vfg->setMimeSourceFactory(&_msf); + insertTab(_vfg, i18n("Voltage-Frequency Graphs")); + + // Pin Diagrams + _pins = new Browser(this); + _pins->setMimeSourceFactory(&_msf); + insertTab(_pins, i18n("Pin Diagrams")); +} + +void DeviceChooser::View::setDevice(const QString &name, bool cannotChangeDevice) +{ + const Device::Data *data = Device::lister().data(name); + if ( data==0 ) return; + QString doc = htmlInfo(*data, (cannotChangeDevice ? QString::null : "device:%1"), Device::documentHtml(*data)); + doc += Device::supportedHtmlInfo(*data); + _info->setText("<html><body>" + doc + "</body></html>"); + doc = htmlVoltageFrequencyGraphs(*data, QString::null, &_msf); + QPixmap pix = data->group().memoryGraph(*data); + QString label = data->name() + "_memory_map.png"; + _msf.setPixmap(label, pix); + _memory->setText("<html><body><img src=\"" + label + "\" /></body></html>"); + _vfg->setText("<html><body>" + doc + "</body></html>"); + doc = htmlPinDiagrams(*data, QString::null, &_msf); + _pins->setText("<html><body>" + doc + "</body></html>"); +} + +void DeviceChooser::View::setText(const QString &text) +{ + _info->setText(text); + _vfg->setText(text); + _pins->setText(text); +} + +void DeviceChooser::View::clear() +{ + _info->clear(); + _vfg->clear(); + _pins->clear(); +} + +//----------------------------------------------------------------------------- +DeviceChooser::Editor::Editor(const QString &title, const QString &tag, QWidget *widget) + : DeviceEditor(title, tag, widget, "device_view_editor") +{} + +QWidget *DeviceChooser::Editor::createView(const Device::Data *, QWidget *parent) +{ + DeviceChooser::View *view = new DeviceChooser::View(parent); + connect(view, SIGNAL(deviceChanged(const QString &)), SIGNAL(deviceChanged(const QString &))); + view->setDevice(_device, true); + return view; +} diff --git a/src/libgui/device_gui.h b/src/libgui/device_gui.h new file mode 100644 index 0000000..a10c58a --- /dev/null +++ b/src/libgui/device_gui.h @@ -0,0 +1,205 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef DEVICE_GUI_H +#define DEVICE_GUI_H + +#include <qpushbutton.h> +#include <qlayout.h> +#include <qcombobox.h> +class QListViewItem; +class QCheckBox; +#include <ktextbrowser.h> +class KListView; + +#include "common/gui/key_gui.h" +#include "common/gui/dialog.h" +#include "device_editor.h" +#include "devices/pic/base/pic.h" +namespace Programmer { class Group; } +namespace Tool { class Group; } + +namespace DeviceChooser +{ + +enum Type { Choose, ChooseWithAuto }; +class View; + +BEGIN_DECLARE_ENUM(ListType) + FamilyTree = 0, Flat +END_DECLARE_ENUM_STD(ListType) + +//----------------------------------------------------------------------------- +class Config : public GenericConfig +{ +public: + Config() : GenericConfig("device_chooser") {} + const Programmer::Group *programmerGroup(); + void writeProgrammerGroup(const Programmer::Group *group); + const Tool::Group *toolGroup(); + void writeToolGroup(const Tool::Group *group); +}; + +//----------------------------------------------------------------------------- +template <typename Enum> +class EnumComboBox +{ +public: + EnumComboBox(const QString &key, QWidget *parent) : _key(key) { + _combo = new QComboBox(parent); + for (Enum type; type<Enum::Nb_Types; ++type) _combo->insertItem(type.label()); + Config config; + Enum type = config.readEnumEntry(key, Enum(Enum::Nb_Types)); + if ( type!=Enum::Nb_Types ) _combo->setCurrentItem(type.type()); + } + EnumComboBox(const QString &emptyLabel, const QString &key, QWidget *parent) : _key(key) { + _combo = new QComboBox(parent); + _combo->insertItem(emptyLabel); + for (Enum type; type<Enum::Nb_Types; ++type) _combo->insertItem(type.label()); + Config config; + Enum type = config.readEnumEntry(key, Enum(Enum::Nb_Types)); + if ( type!=Enum::Nb_Types ) _combo->setCurrentItem(type.type()+1); + } + QComboBox *combo() { return _combo; } + Enum value() const { + if ( _combo->count()==Enum::Nb_Types ) return typename Enum::Type(_combo->currentItem()); + if ( _combo->currentItem()==0 ) return Enum::Nb_Types; + return typename Enum::Type(_combo->currentItem()-1); + } + void reset() { _combo->setCurrentItem(0); } + void writeConfig() { + Config config; + config.writeEnumEntry(_key, value()); + } + +private: + QString _key; + QComboBox *_combo; +}; + +//----------------------------------------------------------------------------- +class Dialog : public ::Dialog +{ +Q_OBJECT +public: + Dialog(const QString &device, Type type, QWidget *parent); + virtual ~Dialog(); + + QString device() const; + +private slots: + void listDoubleClicked(QListViewItem *item); + void currentChanged(QListViewItem *item); + void deviceChange(const QString &device); + void updateList(); + void resetFilters(); + +private: + bool _withAuto; + KeyComboBox<QString> *_programmerCombo, *_toolCombo; + EnumComboBox<ListType> *_listTypeCombo; + EnumComboBox<Device::MemoryTechnology> *_memoryCombo; + EnumComboBox<Device::Status> *_statusCombo; + EnumComboBox<Pic::Feature> *_featureCombo; + KListView *_listView; + View *_deviceView; + + void updateList(const QString &device); + const Programmer::Group *programmerGroup() const; + const Tool::Group *toolGroup() const; +}; + +//----------------------------------------------------------------------------- +class ComboBox : public QComboBox +{ +Q_OBJECT +public: + ComboBox(bool withAuto, QWidget *parent); + void setDevice(const QString &device, const Device::Data *data = 0); + QString device() const; + bool withAuto() const { return _withAuto; } + +private: + bool _withAuto; +}; + +//----------------------------------------------------------------------------- +class Button : public QWidget +{ +Q_OBJECT +public: + Button(bool withAuto, QWidget *parent); + void setDevice(const QString &device) { _combo->setDevice(device); } + QString device() const { return _combo->device(); } + +signals: + void changed(); + +private slots: + void chooseDevice(); + +private: + ComboBox *_combo; +}; + +//----------------------------------------------------------------------------- +class Browser : public KTextBrowser +{ +Q_OBJECT +public: + Browser(QWidget *parent); + +signals: + void deviceChanged(const QString &device); + +public slots: + virtual void setSource(const QString &name); +}; + +//----------------------------------------------------------------------------- +class View : public TabWidget +{ +Q_OBJECT +public: + View(QWidget *parent); + void clear(); + void setText(const QString &text); + void setDevice(const QString &name, bool cannotChangeDevice); + +signals: + void deviceChanged(const QString &device); + +private: + QMimeSourceFactory _msf; + Browser *_info, *_memory, *_vfg, *_pins; +}; + +//----------------------------------------------------------------------------- +class Editor : public DeviceEditor +{ +Q_OBJECT +public: + Editor(const QString &title, const QString &tag, QWidget *parent); + virtual bool isModified() const { return false; } + virtual bool isReadOnly() const { return true; } + virtual void addGui() {} + virtual void removeGui() {} + virtual void setFocus() {} + +signals: + void deviceChanged(const QString &device); + +private: + virtual QWidget *createView(const Device::Data *data, QWidget *parent); + virtual void setModifiedInternal(bool) {} + virtual void setReadOnlyInternal(bool) {} +}; + +} // namespace + +#endif diff --git a/src/libgui/editor.cpp b/src/libgui/editor.cpp new file mode 100644 index 0000000..c64d98f --- /dev/null +++ b/src/libgui/editor.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "editor.h" + +#include <klocale.h> + +#include "common/gui/purl_gui.h" +#include "common/gui/misc_gui.h" + +Editor::Editor(const QString &title, const QString &tag, QWidget *parent, const char *name) + : QWidget(parent, name), _title(title), _tag(tag) +{} + +Editor::Editor(QWidget *parent, const char *name) + : QWidget(parent, name) +{} + +QSizePolicy Editor::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); +} + +void Editor::setModified(bool m) +{ + setModifiedInternal(m); + if (m) emit modified(); +} + +void Editor::setReadOnly(bool ro) +{ + setReadOnlyInternal(ro); + emit guiChanged(); +} + +bool Editor::save() +{ + if ( url().isEmpty() ) return saveAs(); + if ( !save(url()) ) return false; + setModified(false); + emit guiChanged(); + return true; +} + +bool Editor::saveAs() +{ + QString filter = PURL::filter(fileType()); + PURL::Url purl = PURL::getSaveUrl(":save_file_as", filter, this, i18n("Save File"), PURL::AskOverwrite); + if ( purl.isEmpty() ) return false; + if ( !save(purl) ) return false; + setModified(false); + emit guiChanged(); + return true; +} + +bool Editor::slotLoad() +{ + bool readOnly = isReadOnly(); + if ( !open(url()) ) return false; + setModified(false); + setReadOnly(readOnly); + statusChanged(); + emit guiChanged(); + return true; +} + +QString Editor::filename() const +{ + return (url().isEmpty() ? "<" + _title + ">" : "\"" + url().filepath() + "\""); +} + +bool Editor::checkSaved() +{ + if ( !isModified() ) return true; + MessageBox::Result res = MessageBox::questionYesNoCancel(i18n("File %1 not saved.").arg(filename()), + KStdGuiItem::save(), KStdGuiItem::discard()); + if ( res==MessageBox::Cancel ) return false; + if ( res==MessageBox::Yes ) save(); + return true; +} + +bool Editor::reload() +{ + if ( !checkSaved() ) return false; + return slotLoad(); +} diff --git a/src/libgui/editor.h b/src/libgui/editor.h new file mode 100644 index 0000000..9247c80 --- /dev/null +++ b/src/libgui/editor.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef EDITOR_H +#define EDITOR_H + +#include <qlabel.h> +#include <qlayout.h> +#include <qvaluevector.h> +#include "common/common/qflags.h" +#include <kstdaction.h> +class KPopupMenu; + +#include "common/global/purl.h" + +class Editor : public QWidget +{ +Q_OBJECT +public: + Editor(const QString &title, const QString &tag, QWidget *parent, const char *name); + Editor(QWidget *parent, const char *name); + virtual QSizePolicy sizePolicy() const; + virtual PURL::FileType fileType() const = 0; + virtual bool isModified() const = 0; + void setModified(bool modified); + virtual PURL::Url url() const = 0; + QString name() const { return _title; } + QString tag() const { return _tag; } + void setReadOnly(bool readOnly); + virtual bool isReadOnly() const = 0; + bool checkSaved(); + bool reload(); + virtual void setFocus() = 0; + virtual bool open(const PURL::Url &url) = 0; + virtual bool save(const PURL::Url &url) = 0; + virtual void addGui() = 0; + virtual void removeGui() = 0; + virtual QValueList<uint> bookmarkLines() const = 0; + virtual void setBookmarkLines(const QValueList<uint> &lines) = 0; + +public slots: + bool slotLoad(); + bool save(); + bool saveAs(); + void toggleReadOnly() { setReadOnly(!isReadOnly()); } + virtual void statusChanged() = 0; + +signals: + void modified(); + void guiChanged(); + void statusTextChanged(const QString &text); + void dropEventPass(QDropEvent *e); + +protected: + QString filename() const; + virtual void setModifiedInternal(bool modified) = 0; + virtual void setReadOnlyInternal(bool readOnly) = 0; + +private: + QString _title, _tag; +}; + +#endif diff --git a/src/libgui/editor_manager.cpp b/src/libgui/editor_manager.cpp new file mode 100644 index 0000000..2a42554 --- /dev/null +++ b/src/libgui/editor_manager.cpp @@ -0,0 +1,506 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "editor_manager.h" + +#include <qiconset.h> +#include <qdragobject.h> +#include <qpainter.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <kpopupmenu.h> +#include <kaction.h> + +#include "text_editor.h" +#include "hex_editor.h" +#include "object_view.h" +#include "new_dialogs.h" +#include "main_global.h" +#include "gui_debug_manager.h" +#include "common/gui/purl_gui.h" +#include "device_gui.h" +#include "register_view.h" +#include "device_editor.h" +#include "project_manager.h" +#include "global_config.h" +#include "project.h" + +//----------------------------------------------------------------------------- +SwitchToDialog::SwitchToDialog(const QStringList &names, QWidget *parent) + : Dialog(parent, "switch_to_dialog", true, i18n("Switch to editor"), Ok | Cancel, Ok, false) +{ + QVBoxLayout *top = new QVBoxLayout(mainWidget(), 10, 10); + _edit = new KLineEdit(mainWidget()); + _edit->setCompletedItems(names); + top->addWidget(_edit); +} + +//----------------------------------------------------------------------------- +void EditorTabBar::paintLabel(QPainter *p, const QRect &br, QTab *t, bool has_focus) const +{ + QFont f = p->font(); + f.setItalic(_readOnly[t]); + p->setFont(f); + QTabBar::paintLabel(p, br, t, has_focus); +} + +//----------------------------------------------------------------------------- +QString EditorHistory::goBack() +{ + if ( !hasBack() ) return QString::null; + _current--; + return _names[_current]; +} + +QString EditorHistory::goForward() +{ + if ( !hasForward() ) return QString::null; + _current++; + return _names[_current]; +} + +void EditorHistory::add(const QString &name) +{ + if ( _names.count()!=0 ) { + _current = QMIN(_current, _names.count()-1); + if ( _names[_current]==name ) return; + if ( _current!=0 && _names[_current-1]==name ) { + _current--; + return; + } + _current++; + if ( _current<_names.count() && _names[_current]==name ) return; + } + _names.resize(_current+1); + _names[_current] = name; +} + +void EditorHistory::closedLast() +{ + if ( _names.count()==0 ) return; + _names.resize(_current); + if ( _current!=0 ) _current--; +} + +//----------------------------------------------------------------------------- +const char * const EditorManager::EDITOR_TAGS[Nb_EditorTypes] = { "device", "registers" }; + +EditorManager::EditorManager(QWidget *parent) + : TabWidget(parent, "editor_manager"), _current(0) +{ + setTabBar(new EditorTabBar(this)); + connect(this, SIGNAL(currentChanged(QWidget *)), SLOT(showEditor(QWidget *))); + setHoverCloseButton(readConfigEntry(BaseGlobalConfig::ShowTabCloseButton).toBool()); + setHoverCloseButtonDelayed(false); +} + +bool EditorManager::openFile(const PURL::Url &url) +{ + if ( url.isEmpty() ) return false; + Editor *e = findEditor(url); + if (e) { // document already loaded + if ( !MessageBox::askContinue(i18n("File \"%1\" already loaded. Reload?").arg(url.kurl().prettyURL()), + i18n("Warning"), i18n("Reload")) ) return true; + if ( !e->slotLoad() ) { + closeEditor(e, false); + return false; + } + return true; + } + if ( !openEditor(url) ) { + static_cast< KRecentFilesAction *>(Main::action("file_open_recent"))->removeURL(url.kurl()); + return false; + } + static_cast<KRecentFilesAction *>(Main::action("file_open_recent"))->addURL(url.kurl()); + return true; +} + +void EditorManager::connectEditor(Editor *editor) +{ + disconnectEditor(currentEditor()); + if ( editor==0 ) return; + editor->addGui(); + connect(editor, SIGNAL(modified()), SLOT(modifiedSlot())); + connect(editor, SIGNAL(guiChanged()), SIGNAL(guiChanged())); + connect(editor, SIGNAL(dropEventPass(QDropEvent *)), SLOT(slotDropEvent(QDropEvent *))); + connect(editor, SIGNAL(statusTextChanged(const QString &)), SIGNAL(statusChanged(const QString &))); +} + +void EditorManager::modifiedSlot() +{ + emit modified(currentEditor()->url()); +} + +void EditorManager::disconnectEditor(Editor *editor) +{ + if ( editor==0 ) return; + editor->disconnect(this); + editor->removeGui(); +} + +QString EditorManager::title(const Editor &e) const +{ + return (e.url().isEmpty() ? "<" + e.name() + ">" : e.url().filename()); +} + +void EditorManager::updateTitles() +{ + KIconLoader loader; + QPixmap def = loader.loadIcon("piklab", KIcon::Small); + QPixmap modified = loader.loadIcon("filesave", KIcon::Small); + QPixmap chip = loader.loadIcon("piklab_chip", KIcon::Small); + QValueList<Editor *>::iterator it = _editors.begin(); + for (; it!=_editors.end(); ++it) { + static_cast<EditorTabBar *>(tabBar())->setReadOnly(indexOf(*it), (*it)->isReadOnly()); + QPixmap pixmap; + if ( (*it)->isModified() ) pixmap = modified; + else if ( ::qt_cast< ::DeviceEditor *>(*it)==0 ) pixmap = PURL::icon((*it)->fileType()); + else pixmap = chip; + changeTab(*it, pixmap.isNull() ? def : pixmap, title(**it)); + } +} + +bool EditorManager::closeCurrentEditor() +{ + if ( !closeEditor(_current, true) ) return false; + emit guiChanged(); + return true; +} + +bool EditorManager::closeAllEditors() +{ + if ( currentEditor()==0 ) return true; + while ( currentEditor() ) + if ( !closeEditor(currentEditor(), true) ) break; + emit guiChanged(); + return ( currentEditor()==0 ); +} + +bool EditorManager::closeAllOtherEditors() +{ + if ( nbEditors()==1 ) return true; + QValueList<Editor *> list = _editors; + list.remove(currentEditor()); + QValueList<Editor *>::iterator it = list.begin(); + bool ok = true; + for (; it!=list.end(); ++it) { + if ( !closeEditor(*it, true) ) { + ok = false; + break; + } + } + emit guiChanged(); + return ok; +} + +bool EditorManager::closeEditor(const PURL::Url &url) +{ + Editor *e = findEditor(url); + if ( e==0 ) return true; + if ( !closeEditor(e, true) ) return false; + emit guiChanged(); + return true; +} + +void EditorManager::closeRequest(int i) +{ + closeEditor(static_cast<Editor *>(page(i)), true); + emit guiChanged(); +} + +bool EditorManager::closeEditor(Editor *e, bool ask) +{ + if ( e==0 ) return true; + if ( ask && !e->checkSaved() ) return false; + removePage(e); + _editors.remove(e); + Editor *g = static_cast<Editor *>(currentPage()); + changeToEditor(g); + saveBookmarks(*e); + delete e; + return true; +} + +void EditorManager::saveBookmarks(const Editor &e) +{ + if ( Main::project()==0 ) return; + QValueList<uint> lines = e.bookmarkLines(); + Main::project()->setBookmarkLines(e.url(), lines); +} + +void EditorManager::restoreBookmarks(Editor &e) +{ + if ( Main::project()==0 ) return; + QValueList<uint> lines = Main::project()->bookmarkLines(e.url()); + e.setBookmarkLines(lines); +} + +void EditorManager::showEditor(Editor *e) +{ + changeToEditor(e); + emit guiChanged(); +} + +void EditorManager::changeToEditor(Editor *e) +{ + if ( e==_current ) return; + connectEditor(e); + _current = e; + if (e) { + showPage(e); + e->clearFocus(); // force a got focus signal + e->setFocus(); + e->statusChanged(); + _history.add(name(*e)); + } else { + emit statusChanged(QString::null); + _history.closedLast(); + } +} + +Editor *EditorManager::findEditor(const QString &tag) +{ + QValueList<Editor *>::iterator it = _editors.begin(); + for (; it!=_editors.end(); ++it) if ( (*it)->tag()==tag ) return *it; + return 0; +} + +Editor *EditorManager::findEditor(const PURL::Url &url) +{ + QValueList<Editor *>::iterator it = _editors.begin(); + for (; it!=_editors.end(); ++it) if ( (*it)->url()==url ) return *it; + return 0; +} + +Editor *EditorManager::createEditor(PURL::FileType type, const PURL::Url &url) +{ + Editor *e = findEditor(url); + if (e) closeEditor(e, false); + switch (type.type()) { + case PURL::Hex: + e = new HexEditor(this); + break; + case PURL::CSource: + case PURL::CppSource: + case PURL::CHeader: + case PURL::AsmGPAsm: + case PURL::AsmPIC30: + case PURL::AsmPICC: + case PURL::Inc: + case PURL::JalSource: + case PURL::BasicSource: + e = new TextEditor(true, this); + break; + case PURL::Lkr: + case PURL::Gld: + case PURL::Map: + case PURL::Lst: + case PURL::Cod: + case PURL::Unknown: + e = new TextEditor(false, this); + break; + case PURL::Coff: + if ( Main::project()==0 ) { + if ( Main::deviceData()==0 ) return 0; + e = new Coff::CoffEditor(url, *Main::deviceData(), this); + } else { + if ( Debugger::manager->coff()==0 ) return 0; + e = new Coff::CoffEditor(*Debugger::manager->coff(), this); + } + static_cast<Coff::CoffEditor *>(e)->setView(&Main::compileLog()); + break; + case PURL::Object: + e = new Coff::ObjectEditor(url, this); + static_cast<Coff::ObjectEditor *>(e)->setView(&Main::compileLog()); + break; + case PURL::Library: + e = new Coff::LibraryEditor(url, this); + static_cast<Coff::LibraryEditor *>(e)->setView(&Main::compileLog()); + break; + case PURL::Elf: + case PURL::Project: + case PURL::PikdevProject: + case PURL::Nb_FileTypes: break; + } + return e; +} + +void EditorManager::addEditor(Editor *e) +{ + QValueList<Editor *>::iterator it = _editors.begin(); + for (; it!=_editors.end(); ++it) if ( *it==e ) return; + _editors.append(e); + addTab(e, QString::null); + setTabEnabled(e, true); + restoreBookmarks(*e); + showEditor(e); +} + +void EditorManager::slotDropEvent(QDropEvent *event) +{ + QStringList urls; + if ( !QUriDrag::decodeLocalFiles(event, urls)) return; + QStringList::const_iterator it = urls.begin(); + for(; it!=urls.end(); ++it) openEditor(PURL::Url::fromPathOrUrl(*it)); +} + +Editor *EditorManager::openEditor(const PURL::Url &url) +{ + Editor *e = findEditor(url); + if ( e==0 ) { + e = createEditor(url.fileType(), url); + if ( e==0 ) return 0; + if ( !e->open(url) ) { + closeEditor(e, false); + return 0; + } + addEditor(e); + } else showEditor(e); + return e; +} + +void EditorManager::saveAllFiles() +{ + QValueList<Editor *>::iterator it = _editors.begin(); + for (; it!=_editors.end(); ++it) { + if ( !(*it)->isModified() ) continue; + (*it)->save(); + } + emit guiChanged(); +} + +PURL::UrlList EditorManager::files() const +{ + PURL::UrlList names; + QValueList<Editor *>::const_iterator it = _editors.begin(); + for(; it!=_editors.end(); ++it) { + if ( (*it)->url().isEmpty() ) continue; + names.push_back((*it)->url()); + } + return names; +} + +void EditorManager::contextMenu(int i, const QPoint &p) +{ + Editor *editor = static_cast<Editor *>(page(i)); + if ( editor==0 ) return; + + KIconLoader loader; + QPixmap closeIcon = loader.loadIcon("fileclose", KIcon::Small); + QPixmap saveIcon = loader.loadIcon("filesave", KIcon::Small); + QPixmap saveAsIcon = loader.loadIcon("filesaveas", KIcon::Small); + QPixmap reloadIcon = loader.loadIcon("reload", KIcon::Small); + KPopupMenu *popup = new KPopupMenu; + popup->insertTitle(title(*editor)); + popup->insertItem(closeIcon, i18n("Close"), 1); + if ( nbEditors()>1 ) popup->insertItem(i18n("Close All Others"), 2); + if ( editor->isModified() ) popup->insertItem(saveIcon, i18n("Save"), 3); + popup->insertItem(saveAsIcon, i18n("Save As..."), 4); + if ( !editor->url().isEmpty() ) popup->insertItem(reloadIcon, i18n("Reload"), 5); + switch (popup->exec(p)) { + case 1: closeEditor(editor, true); break; + case 2: closeAllOtherEditors(); break; + case 3: editor->save(); break; + case 4: editor->saveAs(); break; + case 5: editor->reload(); break; + } + emit guiChanged(); + delete popup; +} + +void EditorManager::switchHeaderImplementation() +{ + if ( currentEditor()==0 ) return; + PURL::Url url = currentEditor()->url(); + PURL::FileType type = url.fileType(); + PURL::SourceFamily source = type.data().sourceFamily; + if ( type.data().group==PURL::Source ) type = source.data().headerType; + else { + Q_ASSERT( type.data().group==PURL::Source ); + type = Main::toolGroup().implementationType(source.data().toolType); + } + if ( type==PURL::Nb_FileTypes ) return; + url = url.toFileType(type); + if ( !url.exists() ) return; + openEditor(url); +} + +void EditorManager::switchToEditor() +{ + QStringList names; + for (uint i=0; i<_editors.count(); i++) names.append(title(*_editors[i])); + SwitchToDialog dialog(names, this); + if ( dialog.exec()!=QDialog::Accepted ) return; + for (uint i=0; i<names.count(); i++) { + if ( dialog.name()!=names[i] && dialog.name()!=QString("%1").arg(i+1) ) continue; + showEditor(_editors[i]); + return; + } +} + +QString EditorManager::name(const Editor &e) const +{ + return (!e.name().isEmpty() ? e.name() : e.url().filepath()); +} + +void EditorManager::goBack() +{ + Q_ASSERT( _history.hasBack() ); + QString s = _history.goBack(); + for (uint i=0; i<_editors.count(); i++) + if ( s==name(*_editors[i]) ) showEditor(_editors[i]); +} + +void EditorManager::goForward() +{ + Q_ASSERT( _history.hasForward() ); + QString s = _history.goForward(); + for (uint i=0; i<_editors.count(); i++) + if ( s==name(*_editors[i]) ) showEditor(_editors[i]); +} + +Editor *EditorManager::openEditor(EditorType type) +{ + bool created = false; + Editor *e = 0; + QString tag = EDITOR_TAGS[type]; + switch (type) { + case DeviceEditor: { + e = findEditor(tag); + if ( e==0 ) { + e = new DeviceChooser::Editor(i18n("Device"), tag, this); + static_cast<DeviceChooser::Editor *>(e)->setDevice(false); + static_cast<DeviceChooser::Editor *>(e)->setDevice(true); // #### needed to fix GUI glitch ??? + created = true; + } + break; + } + case RegisterEditor: { + e = findEditor(tag); + if ( e==0 ) { + ::BusyCursor bc; + e = new Register::MainView(i18n("Registers"), tag); + static_cast<Debugger::GuiManager *>(Debugger::manager)->addRegisterView(*static_cast<Register::MainView *>(e)); + created = true; + } + break; + } + case Nb_EditorTypes: Q_ASSERT(false); break; + } + if ( e==0 ) return 0; + if (created) { + if ( !e->slotLoad() ) { + delete e; + return 0; + } + addEditor(e); + } else showEditor(e); + return e; +} diff --git a/src/libgui/editor_manager.h b/src/libgui/editor_manager.h new file mode 100644 index 0000000..0d180b9 --- /dev/null +++ b/src/libgui/editor_manager.h @@ -0,0 +1,128 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef EDITOR_MANAGER_H +#define EDITOR_MANAGER_H + +class QEvent; +#include <ktabbar.h> +#include <ktabwidget.h> +#include <klineedit.h> + +#include "text_editor.h" +#include "common/gui/misc_gui.h" +#include "common/gui/dialog.h" + +//----------------------------------------------------------------------------- +class SwitchToDialog : public Dialog +{ +Q_OBJECT +public: + SwitchToDialog(const QStringList &names, QWidget *parent); + QString name() const { return _edit->text(); } + +private: + KLineEdit *_edit; +}; + +//----------------------------------------------------------------------------- +class EditorTabBar : public TabBar +{ +Q_OBJECT +public: + EditorTabBar(QWidget *parent) : TabBar(parent, "editor_tab_bar") {} + void setReadOnly(uint index, bool readOnly) { _readOnly[tabAt(index)] = readOnly; } + +private: + QMap<QTab *, bool> _readOnly; + virtual void paintLabel(QPainter *p, const QRect &br, QTab *t, bool has_focus) const; +}; + +//----------------------------------------------------------------------------- +class EditorHistory +{ +public: + EditorHistory() : _current(0) {} + bool hasBack() const { return _current!=0; } + bool hasForward() const { return (_current+1)<_names.count(); } + void add(const QString &name); + void closedLast(); + QString goBack(); + QString goForward(); + +private: + uint _current; + QValueVector<QString> _names; +}; + +//----------------------------------------------------------------------------- +class EditorManager : public TabWidget +{ +Q_OBJECT +public: + EditorManager(QWidget *parent); + + PURL::UrlList files() const; + QValueList<Editor *> &editors() { return _editors; } + uint nbEditors() const { return _editors.count(); } + Editor *createEditor(PURL::FileType type, const PURL::Url &url); + void addEditor(Editor *e); + Editor *currentEditor() const { return _current; } + Editor *findEditor(const PURL::Url &file); + Editor *findEditor(const QString &tag); + void showEditor(Editor *e); + bool closeEditor(const PURL::Url &url); + bool closeEditor(Editor *e, bool ask); + bool openFile(const PURL::Url &url); + Editor *openEditor(const PURL::Url &url); + void connectEditor(Editor *editor); + void disconnectEditor(Editor *editor); + const EditorHistory &history() const { return _history; } + enum EditorType { DeviceEditor = 0, RegisterEditor, Nb_EditorTypes }; + Editor *openEditor(EditorType type); + +public slots: + void updateTitles(); + void slotDropEvent(QDropEvent *e); + void saveAllFiles(); + bool closeCurrentEditor(); + bool closeAllEditors(); + bool closeAllOtherEditors(); + void switchHeaderImplementation(); + void switchToEditor(); + void goBack(); + void goForward(); + +signals: + void modified(const PURL::Url &url); + void guiChanged(); + void statusChanged(const QString &); + +private: + void changeToEditor(Editor *e); + void enableActions(bool enable); + QString title(const Editor &e) const; + QString name(const Editor &e) const; + virtual void contextMenu(int i, const QPoint &p); + void saveBookmarks(const Editor &e); + void restoreBookmarks(Editor &e); + +private slots: + void showEditor(QWidget *w) { showEditor(static_cast<Editor *>(w)); } + void closeRequest(int i); + void modifiedSlot(); + +private: + Editor *_current; + QValueList<Editor *> _editors; + EditorHistory _history; + static const char * const EDITOR_TAGS[Nb_EditorTypes]; +}; + +#endif diff --git a/src/libgui/global_config.cpp b/src/libgui/global_config.cpp new file mode 100644 index 0000000..8424450 --- /dev/null +++ b/src/libgui/global_config.cpp @@ -0,0 +1,106 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "global_config.h" + +#include <kapplication.h> +#include <kconfig.h> +#include <klocale.h> + +#include "progs/list/prog_list.h" +#include "tools/list/tool_list.h" + +const BaseGlobalConfig::Data BaseGlobalConfig::DATA[Nb_Types] = { + { "auto_rebuild_modified", I18N_NOOP("Automatically rebuild project before programming if it is modified."), QVariant(true, 0) }, + { "program_after_build", I18N_NOOP("Program device after successful build."), QVariant(false, 0) }, + { "user_id_set_to_checksum", I18N_NOOP("Set User Ids to unprotected checksum (if User Ids are empty)."), QVariant(false, 0) }, + { "show_tab_close_buttons", I18N_NOOP("Show close buttons on tabs (need restart to take effect)."), QVariant(true, 0) } +}; + +PURL::Url GlobalConfig::openedProject() +{ + GenericConfig config(QString::null); + return PURL::Url::fromPathOrUrl(config.readEntry("project", QString::null)); +} +void GlobalConfig::writeOpenedProject(const PURL::Url &p) +{ + GenericConfig config(QString::null); + config.writeEntry("project", p.filepath()); +} + +PURL::UrlList GlobalConfig::openedFiles() +{ + GenericConfig config(QString::null); + PURL::UrlList files; + uint i = 0; + for (;;) { + QString file = config.readEntry(QString("file%1").arg(i), QString::null); + if ( file.isEmpty() ) break; + files += PURL::Url::fromPathOrUrl(file); + i++; + } + return files; +} +void GlobalConfig::writeOpenedFiles(const PURL::UrlList &files) +{ + GenericConfig config(QString::null); + for (uint i=0; i<=files.count(); i++) { + QString s = (i==files.count() ? QString::null : files[i].filepath()); + config.writeEntry(QString("file%1").arg(i), s); + } +} + +void GlobalConfig::writeProgrammerGroup(const Programmer::Group &group) +{ + GenericConfig config(QString::null); + config.writeEntry("programmer", group.name()); +} +const Programmer::Group &GlobalConfig::programmerGroup() +{ + GenericConfig config(QString::null); + QString s = config.readEntry("programmer"); + const Programmer::Group *group = Programmer::lister().group(s); + if ( group==0 ) return *Programmer::lister().begin().data(); + return *group; +} + +void GlobalConfig::writeDebugLevel(Log::DebugLevel level) +{ + GenericConfig config(QString::null); + config.writeEnumEntry<Log::DebugLevel>("log_debug_level", level); +} +Log::DebugLevel GlobalConfig::debugLevel() +{ + GenericConfig config(QString::null); + return config.readEnumEntry<Log::DebugLevel>("log_debug_level", Log::DebugLevel::Normal); +} + +void GlobalConfig::writeLogOutputType(Log::OutputType type) +{ + GenericConfig config(QString::null); + config.writeEntry("log_output_type", type); +} +Log::OutputType GlobalConfig::logOutputType() +{ + GenericConfig config(QString::null); + uint output = config.readUIntEntry("log_output_type", Log::GuiOnly); + if ( output>=Log::Nb_OutputTypes ) return Log::GuiOnly; + return Log::OutputType(output); +} + +void GlobalConfig::writeShowLineNumbers(bool show) +{ + GenericConfig config(QString::null); + config.writeEntry("show_line_numbers", show); +} +bool GlobalConfig::showLineNumbers() +{ + GenericConfig config(QString::null); + return config.readBoolEntry("show_line_numbers", false); +} diff --git a/src/libgui/global_config.h b/src/libgui/global_config.h new file mode 100644 index 0000000..8e5cfaa --- /dev/null +++ b/src/libgui/global_config.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef GLOBAL_CONFIG_H +#define GLOBAL_CONFIG_H + +#include "progs/base/generic_prog.h" +#include "common/global/purl.h" +#include "tools/base/tool_group.h" +#include "log_view.h" + +BEGIN_DECLARE_CONFIG(BaseGlobalConfig) + AutoRebuildModified, ProgramAfterBuild, UserIdSetToChecksum, + ShowTabCloseButton +END_DECLARE_CONFIG(BaseGlobalConfig, "") + +namespace GlobalConfig +{ +extern PURL::Url openedProject(); +extern void writeOpenedProject(const PURL::Url &p); +extern PURL::UrlList openedFiles(); +extern void writeOpenedFiles(const PURL::UrlList &files); +extern void writeProgrammerGroup(const Programmer::Group &group); +extern const Programmer::Group &programmerGroup(); +extern void writeDebugLevel(Log::DebugLevel level); +extern Log::DebugLevel debugLevel(); +extern void writeLogOutputType(Log::OutputType type); +extern Log::OutputType logOutputType(); +extern void writeShowLineNumbers(bool show); +extern bool showLineNumbers(); +} // namespace + +#endif diff --git a/src/libgui/gui_debug_manager.cpp b/src/libgui/gui_debug_manager.cpp new file mode 100644 index 0000000..adda68a --- /dev/null +++ b/src/libgui/gui_debug_manager.cpp @@ -0,0 +1,249 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "gui_debug_manager.h" + +#include "toplevel.h" +#include "text_editor.h" +#include "project.h" +#include "tools/list/compile_config.h" +#include "register_view.h" +#include "watch_view.h" +#include "project_manager.h" +#include "editor_manager.h" +#include "main_global.h" +#include "coff/base/text_coff.h" +#include "progs/base/generic_prog.h" +#include "gui_prog_manager.h" +#include "breakpoint_view.h" +#include "progs/base/prog_group.h" + +bool Debugger::GuiManager::addEditor(Editor &editor) +{ + if ( _editors.find(&editor)!=_editors.end() ) return false; + connect(&editor, SIGNAL(destroyed()), SLOT(editorDestroyed())); + _editors.append(&editor); + return true; +} + +void Debugger::GuiManager::addRegisterView(Register::MainView &view) +{ + if ( !addEditor(view) ) return; + updateRegisters(); +} + +void Debugger::GuiManager::addTextEditor(TextEditor &editor) +{ + if ( !addEditor(editor) ) return; + updateView(false); +} + +void Debugger::GuiManager::clearEditors() +{ + QValueList<Editor *>::iterator it = _editors.begin(); + for (; it!=_editors.end(); ++it) (*it)->disconnect(this); + _editors.clear(); +} + +void Debugger::GuiManager::editorDestroyed() +{ + QValueList<Editor *>::iterator it = _editors.begin(); + for (; it!=_editors.end(); ++it) { + if ( (*it)!=sender() ) continue; + _editors.remove(it); + break; + } +} + +void Debugger::GuiManager::updateDevice() +{ + Manager::updateDevice(); + Main::watchView().init(false); +} + +PURL::Url Debugger::GuiManager::coffUrl() const +{ + return Main::projectManager().projectUrl().toFileType(PURL::Coff); +} + +bool Debugger::GuiManager::internalInit() +{ + if ( !Manager::internalInit() ) return false; + if ( !Main::projectManager().contains(coffUrl()) ) + Main::projectManager().addExternalFile(coffUrl(), ProjectManager::Generated); + Main::watchView().init(true); + if ( registerView() ) registerView()->view()->updateView(); + return true; +} + +bool Debugger::GuiManager::checkState(bool &first) +{ + if ( !Debugger::Manager::checkState(first) ) return false; + if ( first && !Main::toolGroup().generateDebugInformation(Main::device()) ) + MessageBox::information(i18n("The toolchain in use does not generate all necessary debugging information with the selected device. This may reduce debugging capabilities."), Log::Show, "doesnt_generate_debug_information"); + return true; +} + +Breakpoint::Data Debugger::GuiManager::currentBreakpointData() +{ + const Breakpoint::Data *data = Main::breakpointsView().currentData(); + if (data) return *data; + TextEditor *editor = ::qt_cast<TextEditor *>(Main::currentEditor()); + Q_ASSERT(editor); + return Breakpoint::Data(editor->url(), editor->cursorLine()); +} + +void Debugger::GuiManager::toggleBreakpoint() +{ + if ( !Main::programmerGroup().isDebugger() ) { + MessageBox::sorry(i18n("You cannot set breakpoints when a debugger is not selected."), Log::Show); + return; + } + Breakpoint::Data data = currentBreakpointData(); + if ( Breakpoint::list().contains(data) ) { + Breakpoint::list().remove(data); + return; + } + Address address; + if ( !checkBreakpoint(data, false, address) ) return; + Breakpoint::list().append(data); + Breakpoint::list().setAddress(data, address); + if (_coff) toggleEnableBreakpoint(); +} + +void Debugger::GuiManager::toggleEnableBreakpoint() +{ + Q_ASSERT(_coff); + Breakpoint::Data data = currentBreakpointData(); + bool isActive = ( Breakpoint::list().state(data)==Breakpoint::Active ); + if ( !Breakpoint::list().address(data).isValid() ) { + if ( !isActive ) MessageBox::sorry(i18n("Breakpoint at non-code line cannot be activated."), Log::Show); + } else { + if ( !isActive ) { + freeActiveBreakpoint(); + Breakpoint::list().setState(data, Breakpoint::Active); + } else Breakpoint::list().setState(data, Breakpoint::Disabled); + } +} + +void Debugger::GuiManager::updateEditorMarks(TextEditor &editor) const +{ + editor.clearBreakpointMarks(); + // update breakpoints + bool reached = false; + for (uint i=0; i<Breakpoint::list().count(); i++) { + const Breakpoint::Data &data = Breakpoint::list().data(i); + int line = -1; + Address address = Breakpoint::list().address(data); + if ( _coff && address.isValid() ) line = _coff->lineForAddress(editor.url(), address); + else if ( data.url==editor.url() ) line = data.line; + Breakpoint::MarkType type = breakpointType(data); + if ( line!=-1 ) editor.setMark(line, type); + if ( type==Breakpoint::BreakpointReached ) reached = true; + } + // update pc + if ( _coff && programmer() && programmer()->isActive() && pc().isInitialized() && !reached + && _currentSourceLines.contains(editor.url()) ) { + int pcline = _currentSourceLines[editor.url()]; + if ( programmer()->state()==Programmer::Halted ) editor.setMark(pcline, Breakpoint::ProgramCounterActive); + else editor.setMark(pcline, Breakpoint::ProgramCounterDisabled); + } +} + +void Debugger::GuiManager::clear() +{ + Manager::clear(); + Main::watchView().init(true); +} + +bool Debugger::GuiManager::update(bool gotoPC) +{ + bool on = (programmer() ? programmer()->isTargetPowerOn() : false); + static_cast<KToggleAction *>(Main::action("prog_power"))->setChecked(on); + return Manager::update(gotoPC); +} + +bool Debugger::GuiManager::checkIfContinueStepping(bool &continueStepping) +{ + if ( Main::toolGroup().generateDebugInformation(Main::device()) ) + return Debugger::Manager::checkIfContinueStepping(continueStepping); + if ( !update(false) ) return false; + continueStepping = false; + return true; +} + +void Debugger::GuiManager::updateView(bool gotoPC) +{ + Main::breakpointsView().updateView(); + bool currentHasPC = false; + QValueList<Editor *>::iterator ite; + for (ite=_editors.begin(); ite!=_editors.end(); ++ite) { + TextEditor *e = ::qt_cast<TextEditor *>(*ite); + if ( e==0 ) continue; + updateEditorMarks(*e); + if ( !_currentSourceLines.contains(e->url()) ) continue; + if (gotoPC) e->setCursor(_currentSourceLines[e->url()], 0); + if ( e==Main::currentEditor() ) currentHasPC = true; + } + if ( programmer()==0 || programmer()->state()!=Programmer::Halted || !pc().isInitialized() || currentHasPC ) return; + // 1: look at files inside project and not generated + // 2: look at files inside project + // 3: look at existing files + for (uint i=0; i<3; i++) { + QMap<PURL::Url, uint>::const_iterator it; + for (it=_currentSourceLines.begin(); it!=_currentSourceLines.end(); ++it) { + switch (i) { + case 0: if ( !Main::projectManager().contains(it.key()) || Main::projectManager().isExternalFile(it.key()) ) continue; break; + case 1: if ( !Main::projectManager().contains(it.key()) ) continue; break; + case 2: if ( !it.key().exists() ) continue; break; + } + TextEditor *e = ::qt_cast<TextEditor *>(Main::editorManager().findEditor(it.key())); + if ( e==0 ) { + if (gotoPC) e = ::qt_cast<TextEditor *>(Main::editorManager().openEditor(it.key())); + if ( e==0 ) continue; + } + updateEditorMarks(*e); + if (gotoPC) { + e->setCursor(_currentSourceLines[e->url()], 0); + Main::editorManager().showEditor(e); + } + return; + } + } +} + +Register::MainView *Debugger::GuiManager::registerView() const +{ + QValueList<Editor *>::const_iterator it = _editors.begin(); + for (; it!=_editors.end(); ++it) { + Register::MainView *rv = ::qt_cast<Register::MainView *>(*it); + if (rv) return rv; + } + return 0; +} + +bool Debugger::GuiManager::isProjectSource(const PURL::Url &url) const +{ + return ( Main::projectManager().contains(url) && !Main::projectManager().isExternalFile(url) ); +} + +void Debugger::GuiManager::showDisassemblyLocation() +{ + TextEditor *editor = ::qt_cast<TextEditor *>(Main::currentEditor()); + Q_ASSERT(editor); + Q_ASSERT(_coff); + QValueVector<Address> addresses = _coff->addresses(editor->url(), editor->cursorLine()); + if ( addresses.isEmpty() ) { + MessageBox::sorry(i18n("Cannot show disassembly location for non-code line."), Log::Show); + return; + } + int line = _coff->lineForAddress(_coff->url(), addresses[0]); + if ( line==-1 ) return; // possible ? + TextEditor *e = ::qt_cast<TextEditor *>(Main::editorManager().openEditor(_coff->url())); + if (e) e->setCursor(line, 0); +} diff --git a/src/libgui/gui_debug_manager.h b/src/libgui/gui_debug_manager.h new file mode 100644 index 0000000..661f86a --- /dev/null +++ b/src/libgui/gui_debug_manager.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef GUI_DEBUG_MANAGER_H +#define GUI_DEBUG_MANAGER_H + +#include "progs/manager/debug_manager.h" +#include "text_editor.h" +#include "main_global.h" +#include "tools/list/compile_process.h" +namespace Register { class MainView; } + +namespace Debugger +{ +class GuiManager : public Manager +{ +Q_OBJECT +public: + GuiManager() {} + virtual void updateDevice(); + void addTextEditor(TextEditor &editor); + void addRegisterView(Register::MainView &view); + void clearEditors(); + virtual void clear(); + +public slots: + virtual bool update(bool gotoPC); + void toggleBreakpoint(); + void toggleEnableBreakpoint(); + void showPC() { updateView(true); } + void showDisassemblyLocation(); + +private slots: + void editorDestroyed(); + +private: + QValueList<Editor *> _editors; + + static Breakpoint::Data currentBreakpointData(); + void updateEditorMarks(TextEditor &editor) const; // return PC line + Register::MainView *registerView() const; + bool addEditor(Editor &editor); + virtual bool internalInit(); + virtual bool checkState(bool &first); + virtual const Programmer::Group *programmerGroup() const { return &Main::programmerGroup(); } + virtual const Device::Data *deviceData() const { return Main::deviceData(); } + virtual PURL::Url coffUrl() const; + virtual Log::View *compileView() { return &Main::compileLog(); } + virtual void updateView(bool gotoPC); + virtual bool isProjectSource(const PURL::Url &url) const; + virtual bool checkIfContinueStepping(bool &continueStepping); +}; + +} // namespace + +#endif diff --git a/src/libgui/gui_prog_manager.cpp b/src/libgui/gui_prog_manager.cpp new file mode 100644 index 0000000..ea22d7e --- /dev/null +++ b/src/libgui/gui_prog_manager.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "gui_prog_manager.h" + +#include <kaction.h> + +#include "progs/base/generic_prog.h" +#include "progs/base/prog_group.h" +#include "progs/base/prog_config.h" +#include "progs/base/hardware_config.h" +#include "progs/base/generic_debug.h" +#include "progs/gui/prog_group_ui.h" +#include "toplevel.h" +#include "project.h" +#include "project_manager.h" +#include "progs/manager/debug_manager.h" + +//---------------------------------------------------------------------------- +bool Programmer::GuiManager::internalInitProgramming(bool debugging) +{ + if ( !Manager::internalInitProgramming(debugging) ) return false; + if ( !debugging && _programmer->isActive() ) { + if ( group().isDebugger() && !askContinue(i18n("The selected operation will stop the debugging session. Continue anyway?")) ) return false; + if ( !halt() ) return false; + } + if ( debugging && !_programmer->isActive() ) { + if ( ::Debugger::manager->coff()==0 && !::Debugger::manager->init() ) { + sorry(i18n("Cannot start debugging without a COFF file. Please compile the project.")); + return false; + } + if ( !group().isSoftware() ) { + if ( !askContinue(i18n("The device memory is in an unknown state. You may want to reprogram the device. Continue anyway?")) ) + return false; + } + } + return true; +} + +void Programmer::GuiManager::toggleDevicePower() +{ + bool on = static_cast<KToggleAction *>(Main::action("prog_power"))->isChecked(); + setDevicePower(on); +} + +void Programmer::GuiManager::showAdvancedDialog() +{ + const ::Programmer::GroupUI *groupui = static_cast<const ::Programmer::GroupUI *>(group().gui()); + const Device::Data *data = Main::deviceData(); + if ( data && !group().isSupported(data->name()) ) data = 0; + createProgrammer(data); + ::Programmer::AdvancedDialog *dialog = groupui->createAdvancedDialog(*_programmer, &Main::toplevel()); + Q_ASSERT(dialog); + dialog->updateDisplay(); + dialog->exec(); + delete dialog; +} + +void Programmer::GuiManager::createProgrammer(const Device::Data *data) +{ + HardwareDescription hd; + hd.port = GroupConfig::portDescription(group()); + ::Hardware::Config *hconfig = group().hardwareConfig(); + if (hconfig) hd.name = hconfig->currentHardware(hd.port.type); + delete hconfig; + Manager::createProgrammer(data, hd); +} diff --git a/src/libgui/gui_prog_manager.h b/src/libgui/gui_prog_manager.h new file mode 100644 index 0000000..b19186e --- /dev/null +++ b/src/libgui/gui_prog_manager.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef GUI_PROG_MANAGER_H +#define GUI_PROG_MANAGER_H + +#include "progs/manager/prog_manager.h" +#include "libgui/main_global.h" + +namespace Programmer +{ +class GuiManager : public Manager +{ +Q_OBJECT +public: + GuiManager(QObject *parent) : Manager(parent) {} + virtual void createProgrammer(const Device::Data *data); + virtual void setState(State state) { Main::setState(state==Idle ? Main::Idle : Main::Programming); } + +public slots: + void toggleDevicePower(); + void showAdvancedDialog(); + +private: + virtual const Group &group() const { return Main::programmerGroup(); } + virtual bool internalInitProgramming(bool debugging); + virtual const Device::Data *device() const { return Main::deviceData(); } +}; + +} // namespace + +#endif diff --git a/src/libgui/hex_editor.cpp b/src/libgui/hex_editor.cpp new file mode 100644 index 0000000..48ad7e8 --- /dev/null +++ b/src/libgui/hex_editor.cpp @@ -0,0 +1,192 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "hex_editor.h" + +#include <qgroupbox.h> +#include <qhgroupbox.h> +#include <qregexp.h> +#include <qlayout.h> +#include <qscrollview.h> +#include <qstringlist.h> +#include <qlabel.h> +#include <qtimer.h> + +#include <klocale.h> +#include <ktempfile.h> + +#include "devices/base/device_group.h" +#include "devices/gui/device_group_ui.h" +#include "devices/gui/hex_view.h" +#include "toplevel.h" +#include "common/global/pfile.h" +#include "main_global.h" + +//----------------------------------------------------------------------------- +HexEditorPart::HexEditorPart(HexEditor *editor) + : KParts::ReadWritePart(editor, "hex_editor_part") +{ + setXMLFile("hexeditorpartui.rc"); + + (void)KStdAction::save(editor, SLOT(save()), actionCollection()); + (void)KStdAction::saveAs(editor, SLOT(saveAs()), actionCollection()); + (void)new KToggleAction(i18n("Read Only Mode"), 0, 0, editor, SLOT(toggleReadOnly()), actionCollection(), "tools_toggle_write_lock"); +} + +void HexEditorPart::setReadWrite(bool rw) +{ + KParts::ReadWritePart::setReadWrite(rw); + static_cast<KToggleAction *>(action("tools_toggle_write_lock"))->setChecked(!rw); +} + +//----------------------------------------------------------------------------- +HexEditor::HexEditor(const QString &name, QWidget *parent) + : DeviceEditor(name, QString::null, parent, "hex_editor") +{ + init(); +} + +HexEditor::HexEditor(QWidget *parent) + : DeviceEditor(parent, "hex_editor") +{ + init(); +} + +void HexEditor::init() +{ + _modified = false; + _memory = 0; + _originalMemory = 0; + _top->addStretch(1); + _part = new HexEditorPart(this); + setReadOnly(false); +} + +void HexEditor::clear() +{ + delete _memory; + _memory = 0; + delete _originalMemory; + _originalMemory = 0; +} + +QWidget *HexEditor::createView(const Device::Data *data, QWidget *parent) +{ + clear(); + if (data) { + _originalMemory = data->group().createMemory(*data); + _memory = data->group().createMemory(*data); + } + if ( data==0 ) return new QWidget(parent); + Device::HexView *hv = Device::groupui(*data).createHexView(*this, parent); + connect(hv, SIGNAL(modified()), SLOT(slotModified())); + _dirty = true; + QTimer::singleShot(0, this, SLOT(simpleLoad())); + return hv; +} + +bool HexEditor::simpleLoad() +{ + if ( !_dirty ) return true; + _dirty = false; + if (_memory) { + QStringList warnings; + if ( _memory->fromHexBuffer(_hexBuffer, warnings)!=Device::Memory::NoWarning ) { + _labelWarning->setText(i18n("<b>Warning:</b> hex file seems to be incompatible with the selected device %1:<br>%2") + .arg(_memory->device().name()).arg(warnings.join("<br>"))); + _labelWarning->show(); + } else _labelWarning->hide(); + display(); + } + return true; +} + +void HexEditor::setReadOnlyInternal(bool readOnly) +{ + _part->setReadWrite(!readOnly); + if (_memory) static_cast<Device::HexView *>(_view)->setReadOnly(readOnly); +} + +void HexEditor::addGui() +{ + Main::toplevel().guiFactory()->addClient(_part); +} + +void HexEditor::removeGui() +{ + Main::toplevel().guiFactory()->removeClient(_part); +} + +bool HexEditor::open(const PURL::Url &url) +{ + _url = url; + PURL::File file(url, Main::compileLog()); + if ( !file.openForRead() ) return false; + QStringList errors; + if ( !_hexBuffer.load(file.stream(), errors) ) { + MessageBox::detailedSorry(i18n("Error(s) reading hex file."), errors.join("\n"), Log::Show); + return false; + } + _dirty = true; + return simpleLoad(); +} + +bool HexEditor::save(const PURL::Url &url) +{ + return save(url, i18n("File URL: \"%1\".").arg(url.pretty())); +} + +bool HexEditor::save(const PURL::Url &url, const QString &fileErrorString) +{ + PURL::File file(url, Main::compileLog()); + if ( !file.openForWrite() ) return false; + if ( !_memory->save(file.stream(), HexBuffer::IHX32) ) { + MessageBox::detailedSorry(i18n("Error while writing file \"%1\".").arg(url.pretty()), fileErrorString, Log::Show); + return false; + } + _originalMemory->copyFrom(*_memory); + _url = url; + return file.close(); +} + +void HexEditor::display() +{ + _modified = false; + if (_memory) { + _originalMemory->copyFrom(*_memory); + static_cast<Device::HexView *>(_view)->display(_memory); + static_cast<Device::HexView *>(_view)->setReadOnly(isReadOnly()); + static_cast<Device::HexView *>(_view)->updateDisplay(); + } + statusChanged(); +} + +void HexEditor::memoryRead() +{ + display(); + emit guiChanged(); +} + +void HexEditor::slotModified() +{ + static_cast<Device::HexView *>(_view)->updateDisplay(); + _modified = true; + statusChanged(); + emit guiChanged(); +} + +void HexEditor::statusChanged() +{ + QString s; + if (_memory) { + BitValue cs = static_cast<Device::HexView *>(_view)->checksum(); + s = i18n("Checksum: %1").arg(toHexLabel(cs, 4)); + } + emit statusTextChanged(s); +} diff --git a/src/libgui/hex_editor.h b/src/libgui/hex_editor.h new file mode 100644 index 0000000..86b7f2c --- /dev/null +++ b/src/libgui/hex_editor.h @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef HEX_EDITOR_H +#define HEX_EDITOR_H + +#include <kparts/part.h> + +#include "device_editor.h" +#include "devices/base/hex_buffer.h" +#include "devices/base/generic_memory.h" + +//----------------------------------------------------------------------------- +class HexEditor; + +class HexEditorPart : public KParts::ReadWritePart +{ +Q_OBJECT +public: + HexEditorPart(HexEditor *editor); + virtual void setReadWrite(bool readWrite); + +private: + virtual bool openFile() { return true; } + virtual bool saveFile() { return true; } +}; + +//----------------------------------------------------------------------------- +class HexEditor : public DeviceEditor +{ +Q_OBJECT +public: + HexEditor(const QString &name, QWidget *parent); + HexEditor(QWidget *parent); + virtual bool isModified() const { return _modified; } + virtual bool isReadOnly() const { return !_part->isReadWrite(); } + virtual ~HexEditor() { clear(); } + virtual PURL::FileType fileType() const { return PURL::Hex; } + virtual PURL::Url url() const { return _url; } + virtual bool save(const PURL::Url &url); + virtual bool open(const PURL::Url &url); + Device::Memory *memory() { return _memory; } + const Device::Memory *memory() const { return _memory; } + const Device::Memory *originalMemory() const { return _originalMemory; } + void memoryRead(); + virtual void addGui(); + virtual void removeGui(); + virtual void setFocus() {} + virtual QValueList<uint> bookmarkLines() const { return QValueList<uint>(); } + virtual void setBookmarkLines(const QValueList<uint> &) {} + +public slots: + virtual void statusChanged(); + +private slots: + void slotModified(); + bool simpleLoad(); + +private: + Device::Memory *_originalMemory, *_memory; + HexBuffer _hexBuffer; + bool _modified, _dirty; + HexEditorPart *_part; + PURL::Url _url; + + virtual void dropEvent(QDropEvent *e) { emit dropEventPass(e); } + bool save(const PURL::Url &url, const QString &fileErrorString); + bool verifyDeviceType(); + virtual QWidget *createView(const Device::Data *data, QWidget *parent); + virtual void setModifiedInternal(bool modified) { _modified = modified; } + virtual void setReadOnlyInternal(bool readOnly); + void display(); + void init(); + void clear(); +}; + +#endif diff --git a/src/libgui/likeback.cpp b/src/libgui/likeback.cpp new file mode 100644 index 0000000..eac86ff --- /dev/null +++ b/src/libgui/likeback.cpp @@ -0,0 +1,668 @@ +/*************************************************************************** + * Copyright (C) 2006 by S�bastien Laot * + * slaout@linux62.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include <kapplication.h> +#include <kaboutdata.h> +#include <kconfig.h> +#include <kiconloader.h> +#include <kaboutdata.h> +#include <klocale.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <qlayout.h> +#include <qtoolbutton.h> +#include <qpushbutton.h> +#include <qpopupmenu.h> +#include <qtextedit.h> +#include <qlayout.h> +#include <qlabel.h> +#include <kdialogbase.h> +#include <qhttp.h> +#include <kurl.h> +#include <kinputdialog.h> +#include <qvalidator.h> +#include <kdebug.h> +#include <kprocess.h> +#include "netwm.h" + +#include <pwd.h> + +#include <iostream> + +#include "likeback.h" + +#include <krun.h> +#include "common/global/about.h" + +LikeBack::LikeBack(Button buttons) + : QWidget( 0, "LikeBack", Qt::WX11BypassWM | Qt::WStyle_NoBorder | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop | Qt::WStyle_NoBorder | Qt::Qt::WGroupLeader) + , m_buttons(buttons) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + + QIconSet likeIconSet = kapp->iconLoader()->loadIconSet("likeback_like", KIcon::Small); + QIconSet dislikeIconSet = kapp->iconLoader()->loadIconSet("likeback_dislike", KIcon::Small); + QIconSet bugIconSet = kapp->iconLoader()->loadIconSet("likeback_bug", KIcon::Small); +// QIconSet configureIconSet = kapp->iconLoader()->loadIconSet("configure", KIcon::Small); + + QToolButton *m_likeButton = new QToolButton(this, "ilike"); + m_likeButton->setIconSet(likeIconSet); + m_likeButton->setTextLabel(i18n("I Like...")); + m_likeButton->setAutoRaise(true); + connect( m_likeButton, SIGNAL(clicked()), this, SLOT(iLike()) ); + layout->add(m_likeButton); + + QToolButton *m_dislikeButton = new QToolButton(this, "idonotlike"); + m_dislikeButton->setIconSet(dislikeIconSet); + m_dislikeButton->setTextLabel(i18n("I Do not Like...")); + m_dislikeButton->setAutoRaise(true); + connect( m_dislikeButton, SIGNAL(clicked()), this, SLOT(iDoNotLike()) ); + layout->add(m_dislikeButton); + + QToolButton *m_bugButton = new QToolButton(this, "ifoundabug"); + m_bugButton->setIconSet(bugIconSet); + m_bugButton->setTextLabel(i18n("I Found a Bug...")); + m_bugButton->setAutoRaise(true); + connect( m_bugButton, SIGNAL(clicked()), this, SLOT(iFoundABug()) ); + layout->add(m_bugButton); + + m_configureButton = new QToolButton(this, "configure"); + QIconSet helpIconSet = kapp->iconLoader()->loadIconSet("help", KIcon::Small); + m_configureButton->setIconSet(helpIconSet); + m_configureButton->setTextLabel(i18n("Configure...")); + m_configureButton->setAutoRaise(true); + connect( m_likeButton, SIGNAL(clicked()), this, SLOT(configure()) ); + layout->add(m_configureButton); + + QPopupMenu *configureMenu = new QPopupMenu(this); + configureMenu->insertItem(helpIconSet, i18n("What's &This?"), this , SLOT(showWhatsThisMessage()) ); + QIconSet changeEmailIconSet = kapp->iconLoader()->loadIconSet("mail_generic", KIcon::Small); + configureMenu->insertItem(changeEmailIconSet, i18n("&Configure Email Address..."), this , SLOT(askEMail()) ); +// QIconSet dontHelpIconSet = kapp->iconLoader()->loadIconSet("stop", KIcon::Small); +// configureMenu->insertItem( dontHelpIconSet, i18n("&Do not Help Anymore"), this , SLOT(doNotHelpAnymore()) ); + m_configureButton->setPopup(configureMenu); + connect( m_configureButton, SIGNAL(pressed()), this, SLOT(openConfigurePopup()) ); + + if (!emailAddressAlreadyProvided()) + //beginFetchingEmail(); // Begin before showing the message, so we have time! + endFetchingEmailFrom(); + +// static const char *messageShown = "LikeBack_starting_information"; +// if (KMessageBox::shouldBeShownContinue(messageShown)) { +// showInformationMessage(); +// KMessageBox::saveDontShowAgainContinue(messageShown); +// } + + resize(sizeHint()); + + connect( &m_timer, SIGNAL(timeout()), this, SLOT(autoMove()) ); + m_timer.start(10); + + s_instance = this; +} + +LikeBack::~LikeBack() +{ +} + +void LikeBack::openConfigurePopup() +{ + m_configureButton->openPopup(); +} + +void LikeBack::doNotHelpAnymore() +{ + disable(); + int result = KMessageBox::questionYesNo( + kapp->activeWindow(), + i18n("Are you sure you do not want to participate anymore in the application enhancing program?"), + i18n("Do not Help Anymore")); + if (result == KMessageBox::No) { + enable(); + return; + } + + s_config->setGroup("LikeBack"); + s_config->writeEntry("userWantToParticipateForVersion_" + s_about->version(), false); + deleteLater(); +} + +void LikeBack::showWhatsThisMessage() +{ + disable(); + showInformationMessage(); + enable(); +} + +bool LikeBack::userWantToParticipate() +{ + if (!kapp) + return true; + + s_config->setGroup("LikeBack"); + return s_config->readBoolEntry("userWantToParticipateForVersion_" + s_about->version(), true); +} + +// TODO: Only show relevant buttons! + +void LikeBack::showInformationMessage() +{ + QPixmap likeIcon = kapp->iconLoader()->loadIcon("likeback_like", KIcon::Small); + QPixmap dislikeIcon = kapp->iconLoader()->loadIcon("likeback_dislike", KIcon::Small); + QPixmap bugIcon = kapp->iconLoader()->loadIcon("likeback_bug", KIcon::Small); + QMimeSourceFactory::defaultFactory()->setPixmap("likeback_icon_like", likeIcon); + QMimeSourceFactory::defaultFactory()->setPixmap("likeback_icon_dislike", dislikeIcon); + QMimeSourceFactory::defaultFactory()->setPixmap("likeback_icon_bug", bugIcon); + KMessageBox::information(0, + "<p><b>" + i18n("This is a quick feedback system for %1.").arg(s_about->programName()) + "</b></p>" + "<p>" + i18n("To help us improve it, your comments are important.") + "</p>" + "<p>" + i18n("Each time you have a great or frustrating experience, " + "please click the appropriate hand below the window title-bar, " + "briefly describe what you like or dislike and click Send.") + "</p>" + "<p><b>" + i18n("Icons description:") + "</b><table>" + "<tr><td><nobr><img source=\"likeback_icon_like\">: " + i18n("Send a comment about what you like.") + "</nobr></td></tr>" + "<tr><td><nobr><img source=\"likeback_icon_dislike\">: " + i18n("Send a comment about what you don't like.") + "</nobr></td></tr>" + "<tr><td><nobr><img source=\"likeback_icon_bug\">: " + i18n("Report a bug.") + "</nobr></td></tr>" + "</table></p>", + i18n("Help Improve the Application")); + QMimeSourceFactory::defaultFactory()->setData("likeback_icon_like", 0L); + QMimeSourceFactory::defaultFactory()->setData("likeback_icon_dislike", 0L); + QMimeSourceFactory::defaultFactory()->setData("likeback_icon_bug", 0L); +} + +QString LikeBack::s_customLanguageMessage = QString(); +bool LikeBack::s_allowFeatureWishes = false; +LikeBack::WindowListing LikeBack::s_windowListing = LikeBack::NoListing; +QString LikeBack::s_hostName = QString(); +QString LikeBack::s_remotePath = QString(); +Q_UINT16 LikeBack::s_hostPort = 16; +int LikeBack::s_disabledCount = 0; +LikeBack* LikeBack::s_instance = 0; +KConfig* LikeBack::s_config = 0; +KAboutData* LikeBack::s_about = 0; + +LikeBack* LikeBack::instance() +{ + return s_instance; +} + +QString LikeBack::customLanguageMessage() +{ + return s_customLanguageMessage; +} + +QString LikeBack::hostName() +{ + return s_hostName; +} + +QString LikeBack::remotePath() +{ + return s_remotePath; +} + +Q_UINT16 LikeBack::hostPort() +{ + return s_hostPort; +} + +KAboutData* LikeBack::about() +{ + return s_about; +} + +void LikeBack::disable() +{ + s_disabledCount++; +} + +void LikeBack::enable() +{ + s_disabledCount--; + if (s_disabledCount < 0) + std::cerr << "===== LikeBack ===== Enabled too many times (less than how many times it was disabled)" << std::endl; +} + +bool LikeBack::enabled() +{ + return s_disabledCount == 0; +} + +void LikeBack::setServer(QString hostName, QString remotePath, Q_UINT16 hostPort) +{ + s_hostName = hostName; + s_remotePath = remotePath; + s_hostPort = hostPort; +} + +void LikeBack::setWindowNamesListing(WindowListing windowListing) +{ + s_windowListing = windowListing; +} + +void LikeBack::setCustomLanguageMessage(const QString &message) +{ + s_customLanguageMessage = message; +} + +void LikeBack::setAllowFeatureWishes(bool allow) +{ + s_allowFeatureWishes = allow; +} + +bool LikeBack::allowFeatureWishes() +{ + return s_allowFeatureWishes; +} + +void LikeBack::autoMove() +{ + static QWidget *lastWindow = 0; + + QWidget *window = kapp->activeWindow(); + // When a Kicker applet has the focus, like the Commandline QLineEdit, + // the systemtray icon indicates to be the current window and the LikeBack is shown next to the system tray icon. + // It's obviously bad ;-) : + bool shouldShow = false;//(enabled() && window && window->inherits("KMainWindow") ); + if (shouldShow) { + //move(window->x() + window->width() - 100 - width(), window->y()); + //move(window->x() + window->width() - 100 - width(), window->mapToGlobal(QPoint(0, 0)).y() - height()); + move(window->mapToGlobal(QPoint(0, 0)).x() + window->width() - width(), window->mapToGlobal(QPoint(0, 0)).y() + 1); + + if (window != lastWindow && s_windowListing != NoListing) +// if (qstricmp(window->name(), "") == 0 || qstricmp(window->name(), "unnamed") == 0) ; +// std::cout << "===== LikeBack ===== UNNAMED ACTIVE WINDOW OF TYPE " << window->className() << " ======" << activeWindowPath() << std::endl; +// else if (s_windowListing == AllWindows) ; +// std::cout << "LikeBack: Active Window: " << activeWindowPath() << std::endl; + lastWindow = window; + } + if (shouldShow && !isShown()) { + show(); + } else if (!shouldShow && isShown()) + hide(); +} + +void LikeBack::iLike() +{ + showDialog(ILike); +} + +void LikeBack::iDoNotLike() +{ + showDialog(IDoNotLike); +} + +void LikeBack::iFoundABug() +{ + (void)new KRun(Piklab::URLS[Piklab::BugReport], kapp->mainWidget()); + // showDialog(IFoundABug); +} + +void LikeBack::configure() +{ +} + +QString LikeBack::activeWindowPath() +{ + QStringList windowNames; + QWidget *window = kapp->activeWindow(); + while (window) { + QString name = window->name(); + if (name == "unnamed") + name += QString(":") + window->className(); + windowNames.append(name); + window = dynamic_cast<QWidget*>(window->parent()); + } + + QString windowName; + for (int i = ((int)windowNames.count()) - 1; i >= 0; i--) { + if (windowName.isEmpty()) + windowName = windowNames[i]; + else + windowName += QString("~~") + windowNames[i]; + } + + return windowName; +} + +void LikeBack::showDialog(Button button) +{ + LikeBackDialog dialog(button, activeWindowPath(), ""); + disable(); + hide(); + kapp->processEvents(); + dialog.exec(); + enable(); +} + +bool LikeBack::emailAddressAlreadyProvided() +{ + return s_config->readBoolEntry("emailAlreadyAsked", false); +} + +QString LikeBack::emailAddress() +{ + if (!emailAddressAlreadyProvided()) + instance()->askEMail(); + + return s_config->readEntry("emailAddress", ""); +} + +void LikeBack::setEmailAddress(const QString &address) +{ + s_config->setGroup("LikeBack"); + s_config->writeEntry("emailAddress", address); + s_config->writeEntry("emailAlreadyAsked", true); +} + +void LikeBack::askEMail() +{ + s_config->setGroup("LikeBack"); + + QString currentEMailAddress = s_config->readEntry("emailAddress", ""); + if (!emailAddressAlreadyProvided() && !instance()->m_fetchedEmail.isEmpty()) + currentEMailAddress = instance()->m_fetchedEmail; + + bool ok; + + QString mailExpString = "[\\w-\\.]+@[\\w-\\.]+\\.[\\w]+"; + //QString namedMailExpString = "[.]*[ \\t]+<" + mailExpString + ">"; + //QRegExp mailExp("^(|" + mailExpString + "|" + namedMailExpString + ")$"); + QRegExp mailExp("^(|" + mailExpString + ")$"); + QRegExpValidator emailValidator(mailExp, this); + + disable(); + QString email = KInputDialog::getText( + i18n("Set Email Address"), + "<p><b>" + i18n("Please provide your email address.") + "</b></p>" + + "<p>" + i18n("It will only be used to contact you back if more information is needed about your comments, how to reproduce the bugs you report, send bug corrections for you to test...") + "</p>" + + "<p>" + i18n("The email address is optional. If you do not provide any, your comments will be sent anonymously. Just click OK in that case.") + "</p>" + + "<p>" + i18n("You can change or remove your email address whenever you want. For that, use the little arrow icon at the top-right corner of a window.") + "</p>" + + "<p>" + i18n("Your email address (keep empty to post comments anonymously):"), + currentEMailAddress, &ok, kapp->activeWindow(), /*name=*/(const char*)0, &emailValidator); + enable(); + + if (ok) + setEmailAddress(email); +} + +// FIXME: Should be moved to KAboutData? Cigogne will also need it. +bool LikeBack::isDevelopmentVersion(const QString &version) +{ + QString theVersion = (version.isEmpty() ? s_about->version() : version); + + return theVersion.find("alpha", /*index=*/0, /*caseSensitive=*/false) != -1 || + theVersion.find("beta", /*index=*/0, /*caseSensitive=*/false) != -1 || + theVersion.find("rc", /*index=*/0, /*caseSensitive=*/false) != -1 || + theVersion.find("svn", /*index=*/0, /*caseSensitive=*/false) != -1 || + theVersion.find("cvs", /*index=*/0, /*caseSensitive=*/false) != -1; +} + +void LikeBack::init(KConfig* config, KAboutData* about, Button buttons) +{ + s_config = config; + s_about = about; + init(isDevelopmentVersion(), buttons); +} + +void LikeBack::init(Button buttons) +{ + init(isDevelopmentVersion(), buttons); +} + +void LikeBack::init(bool isDevelopmentVersion, Button buttons) +{ + if (s_config == 0) + s_config = kapp->config(); + if (s_about == 0) + s_about = (KAboutData*) kapp->aboutData(); + + if (LikeBack::userWantToParticipate() && isDevelopmentVersion) + new LikeBack(buttons); +} + + + + + + + +/** + * Code from KBugReport::slotConfigureEmail() in kdeui/kbugreport.cpp: + */ +/*void LikeBack::beginFetchingEmail() +{ + if (m_process) + return; + m_process = new KProcess(); + *m_process << QString::fromLatin1("kcmshell") << QString::fromLatin1("kcm_useraccount"); + connect( m_process, SIGNAL(processExited(KProcess*)), SLOT(endFetchingEmailFrom()) ); + if (!m_process->start()) { + kdDebug() << "Couldn't start kcmshell.." << endl; + delete m_process; + m_process = 0; + return; + } +// m_configureEmail->setEnabled(false); +}*/ + +/** + * Code from KBugReport::slotSetFrom() in kdeui/kbugreport.cpp: + */ +void LikeBack::endFetchingEmailFrom() +{ +// delete m_process; +// m_process = 0; +// m_configureEmail->setEnabled(true); + + // ### KDE4: why oh why is KEmailSettings in kio? + KConfig emailConf( QString::fromLatin1("emaildefaults") ); + + // find out the default profile + emailConf.setGroup(QString::fromLatin1("Defaults")); + QString profile = QString::fromLatin1("PROFILE_"); + profile += emailConf.readEntry(QString::fromLatin1("Profile"), QString::fromLatin1("Default")); + + emailConf.setGroup(profile); + QString fromaddr = emailConf.readEntry(QString::fromLatin1("EmailAddress")); + if (fromaddr.isEmpty()) { + struct passwd *p; + p = getpwuid(getuid()); + m_fetchedEmail = QString::fromLatin1(p->pw_name); + } else { + QString name = emailConf.readEntry(QString::fromLatin1("FullName")); + if (!name.isEmpty()) + m_fetchedEmail = /*name + QString::fromLatin1(" <") +*/ fromaddr /*+ QString::fromLatin1(">")*/; + } +// m_from->setText( fromaddr ); +} + + + + + + + +/** class LikeBackDialog: */ + +LikeBackDialog::LikeBackDialog(LikeBack::Button reason, QString windowName, QString context) + : KDialog(kapp->activeWindow(), "_likeback_feedback_window_") + , m_reason(reason) + , m_windowName(windowName) + , m_context(context) +{ + setModal(true); + QVBoxLayout *mainLayout = new QVBoxLayout(this); + + QWidget *coloredWidget = new QWidget(this); + QLabel *explainings = new QLabel(this); + QHBoxLayout *explainingLayout = new QHBoxLayout((QWidget*)0, KDialogBase::marginHint()); + explainingLayout->addWidget(explainings); + mainLayout->addWidget(coloredWidget); + + QColor color; + QColor lineColor; + QPixmap icon; + QString title; + QString please; + switch (reason) { + case LikeBack::ILike: + color = QColor("#DFFFDF"); + lineColor = Qt::green; + icon = kapp->iconLoader()->loadIcon("likeback_like", KIcon::Small); + title = i18n("I like..."); + please = i18n("Please briefly describe what you like."); + break; + case LikeBack::IDoNotLike: + color = QColor("#FFDFDF"); + lineColor = Qt::red; + icon = kapp->iconLoader()->loadIcon("likeback_dislike", KIcon::Small); + title = i18n("I do not like..."); + please = i18n("Please briefly describe what you do not like."); + break; + case LikeBack::IFoundABug: + color = QColor("#C0C0C0"); + lineColor = Qt::black; + icon = kapp->iconLoader()->loadIcon("bug", KIcon::Small); + title = i18n("I found a bug..."); + please = i18n("Please briefly describe the bug you encountered."); + break; + case LikeBack::Configure: + case LikeBack::AllButtons: + return; + } + + QWidget *line = new QWidget(this); + line->setPaletteBackgroundColor(lineColor); + line->setFixedHeight(1); + mainLayout->addWidget(line); + mainLayout->addLayout(explainingLayout); + + QHBoxLayout *titleLayout = new QHBoxLayout(0); + coloredWidget->setPaletteBackgroundColor(color); + QLabel *iconLabel = new QLabel(coloredWidget); + iconLabel->setPixmap(icon); + QLabel *titleLabel = new QLabel(title, coloredWidget); + QFont font = titleLabel->font(); + font.setBold(true); + titleLabel->setFont(font); + titleLabel->setPaletteForegroundColor(Qt::black); + titleLayout->addWidget(iconLabel); + titleLayout->addSpacing(4); + titleLayout->addWidget(titleLabel); + titleLayout->addStretch(); + + QVBoxLayout *coloredWidgetLayout = new QVBoxLayout(coloredWidget); + coloredWidgetLayout->setMargin(KDialogBase::marginHint()); + coloredWidgetLayout->setSpacing(KDialogBase::spacingHint()); + coloredWidgetLayout->addLayout(titleLayout); + + QHBoxLayout *commentLayout = new QHBoxLayout((QWidget*)0); + commentLayout->setMargin(0); + commentLayout->setSpacing(KDialogBase::spacingHint()); + m_comment = new QTextEdit(coloredWidget); + QIconSet sendIconSet = kapp->iconLoader()->loadIconSet("mail_send", KIcon::Toolbar); + m_sendButton = new QPushButton(sendIconSet, i18n("Send"), coloredWidget); + m_sendButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + m_sendButton->setEnabled(false); + connect( m_sendButton, SIGNAL(clicked()), this, SLOT(send()) ); + connect( m_comment, SIGNAL(textChanged()), this, SLOT(commentChanged()) ); + commentLayout->addWidget(m_comment); + commentLayout->addWidget(m_sendButton); + coloredWidgetLayout->addLayout(commentLayout); + + explainings->setText( + "<p>" + please + " " + + (LikeBack::customLanguageMessage().isEmpty() ? + i18n("Only english language is accepted.") : + LikeBack::customLanguageMessage() + ) + " " + + (reason == LikeBack::ILike || reason == LikeBack::IDoNotLike ? + i18n("Note that to improve this application, it's important to tell us the things you like as much as the things you dislike.") + " " : + "" + ) + + (LikeBack::allowFeatureWishes() ? + "" : + i18n("Do not ask for features: your wishes will be ignored.") + ) + "</p>" + ); + + resize(kapp->desktop()->width() / 2, kapp->desktop()->height() / 3); + + setCaption(kapp->makeStdCaption(i18n("Send a Comment"))); + // setMinimumSize(mainLayout->sizeHint()); // FIXME: Doesn't work! +} + +LikeBackDialog::~LikeBackDialog() +{ +} + +QHttp *http ; + +void LikeBackDialog::send() +{ + QString emailAddress = LikeBack::instance()->emailAddress(); + + QString type = (m_reason == LikeBack::ILike ? "Like" : (m_reason == LikeBack::IDoNotLike ? "Dislike" : "Bug")); + QString data = + "protocol=" + KURL::encode_string("1.0") + "&" + + "type=" + KURL::encode_string(type) + "&" + + "version=" + KURL::encode_string(LikeBack::about()->version()) + "&" + + "locale=" + KURL::encode_string(KGlobal::locale()->language()) + "&" + + "window=" + KURL::encode_string(m_windowName) + "&" + + "context=" + KURL::encode_string(m_context) + "&" + + "comment=" + KURL::encode_string(m_comment->text()) + "&" + + "email=" + KURL::encode_string(emailAddress); + //QByteArray *data = new QByteArray(); + /*QHttp **/http = new QHttp(LikeBack::hostName(), LikeBack::hostPort()); + +// std::cout << "http://" << LikeBack::hostName() << ":" << LikeBack::hostPort() << LikeBack::remotePath() << std::endl; +// std::cout << data << std::endl; + connect( http, SIGNAL(requestFinished(int, bool)), this, SLOT(requestFinished(int, bool)) ); +// http->post(LikeBack::remotePath(), data.utf8()); + + QHttpRequestHeader header("POST", LikeBack::remotePath()); + header.setValue("Host", LikeBack::hostName()); + header.setValue("Content-Type", "application/x-www-form-urlencoded"); + http->setHost(LikeBack::hostName()); + http->request(header, data.utf8()); + + + m_comment->setEnabled(false); +} + +void LikeBackDialog::requestFinished(int /*id*/, bool error) +{ + // TODO: Save to file if error (connection not present at the moment) + m_comment->setEnabled(true); + LikeBack::disable(); + if (error) { + KMessageBox::error(this, i18n("<p>Error while trying to send the report.</p><p>Please retry later.</p>"), i18n("Transfer Error")); + } else { + KMessageBox::information(this, i18n("<p>Your comment has been sent successfully. It will help improve the application.</p><p>Thanks for your time.</p>") /*+ QString(http->readAll())*/, i18n("Comment Sent")); + close(); + } + LikeBack::enable(); +} + +void LikeBackDialog::commentChanged() +{ + m_sendButton->setEnabled(!m_comment->text().isEmpty()); +} diff --git a/src/libgui/likeback.h b/src/libgui/likeback.h new file mode 100644 index 0000000..70a68dd --- /dev/null +++ b/src/libgui/likeback.h @@ -0,0 +1,120 @@ +/*************************************************************************** + * Copyright (C) 2006 by Sébastien Laot * + * slaout@linux62.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef LIKEBACK_H +#define LIKEBACK_H + +#include <kdialog.h> +#include <qtimer.h> + +class QTextEdit; +class QToolButton; +class QPushButton; +class KProcess; +class KConfig; +class KAboutData; + +/** + * @author S�astien Laot <slaout@linux62.org> + */ +class LikeBack : public QWidget +{ + Q_OBJECT + public: + enum Button { ILike = 0x01, IDoNotLike = 0x02, IFoundABug = 0x04, Configure = 0x10, + AllButtons = ILike | IDoNotLike | IFoundABug | Configure }; + enum WindowListing { NoListing, WarnUnnamedWindows, AllWindows }; + LikeBack(Button buttons = AllButtons); + ~LikeBack(); + static void showInformationMessage(); + static LikeBack* instance(); + static QString customLanguageMessage(); + static bool allowFeatureWishes(); + static QString hostName(); + static QString remotePath(); + static Q_UINT16 hostPort(); + static void setServer(QString hostName, QString remotePath, Q_UINT16 hostPort = 80); + static void setWindowNamesListing(WindowListing windowListing); + static void setCustomLanguageMessage(const QString &message); + static void setAllowFeatureWishes(bool allow); + static bool enabled(); + static void disable(); + static void enable(); + static bool userWantToParticipate(); /// << @Returns true if the user have not disabled LikeBack for this version + static bool emailAddressAlreadyProvided(); + static QString emailAddress(); /// << @Returns the email user address, or ask it to the user if he haven't provided or ignored it + static void setEmailAddress(const QString &address); /// << Calling emailAddress() will ask it to the user the first time + static bool isDevelopmentVersion(const QString &version = QString::null); /// << @Returns true if version is an alpha/beta/rc/svn/cvs version. Use kapp->aboutData()->version is @p version is empty + static void init(Button buttons = AllButtons); /// << Initialize the LikeBack system: enable it if the application version is a development one. + static void init(bool isDevelopmentVersion, Button buttons = AllButtons); /// << Initialize the LikeBack system: enable it if @p isDevelopmentVersion is true. + static void init(KConfig* config, KAboutData* about, Button buttons = AllButtons); + static QString activeWindowPath(); + static KAboutData* about(); + public slots: + void iLike(); + void iDoNotLike(); + void iFoundABug(); + void configure(); + + private slots: + void autoMove(); + void showDialog(Button button); + void openConfigurePopup(); + void doNotHelpAnymore(); + void showWhatsThisMessage(); + void askEMail(); +// void beginFetchingEmail(); + void endFetchingEmailFrom(); // static QString fetchingEmail(); + private: + QTimer m_timer; + Button m_buttons; + QToolButton *m_configureButton; + QString m_fetchedEmail; + KProcess *m_process; + static QString s_hostName; + static QString s_remotePath; + static Q_UINT16 s_hostPort; + static QString s_customLanguageMessage; + static bool s_allowFeatureWishes; + static WindowListing s_windowListing; + static LikeBack *s_instance; + static int s_disabledCount; + static KConfig *s_config; + static KAboutData *s_about; +}; + +class LikeBackDialog : public KDialog +{ + Q_OBJECT + public: + LikeBackDialog(LikeBack::Button reason, QString windowName, QString context); + ~LikeBackDialog(); + private: + LikeBack::Button m_reason; + QTextEdit *m_comment; + QPushButton *m_sendButton; + QString m_windowName; + QString m_context; + private slots: + void send(); + void requestFinished(int id, bool error); + void commentChanged(); +}; + +#endif // LIKEBACK_H diff --git a/src/libgui/log_view.cpp b/src/libgui/log_view.cpp new file mode 100644 index 0000000..158c281 --- /dev/null +++ b/src/libgui/log_view.cpp @@ -0,0 +1,135 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "log_view.h" + +#include <qpopupmenu.h> +#include <qeventloop.h> +#include <qapplication.h> +#include <kiconloader.h> + +#include "global_config.h" +#include "common/gui/purl_gui.h" +#include "common/gui/misc_gui.h" + +Log::Widget::Widget(QWidget *parent, const char *name) + : QTextEdit(parent, name) +{ + setTextFormat(LogText); + setMinimumWidth(300); +} + +void Log::Widget::updateDebugLevel() +{ + setDebugLevel(GlobalConfig::debugLevel()); +} + +void Log::Widget::logExtra(const QString &text) +{ + _text += text; + if ( GlobalConfig::logOutputType()==GuiConsole ) fprintf(stdout, "%s", text.latin1()); +} + +void Log::Widget::doLog(LineType type, const QString &text, Action action) +{ + doLog(text, type.data().color, type.data().bold, action); +} + +void Log::Widget::doLog(DebugLevel level, const QString &text, Action action) +{ + doLog(text, level.data().color, false, action); +} + +void Log::Widget::doLog(const QString &text, const QString &color, bool bold, Action action) +{ + logExtra(text + "\n"); + QString s = QString("<font color=%1>").arg(color); + if (bold) s += "<b>"; + s += escapeXml(text); + if (bold) s += "</b>"; + s += "</font>"; + QTextEdit::append(s); + updateContents(); // #### fix bug in Qt (display is messed up) + ensureVisible(0, contentsHeight()); + if ( action==Immediate) + QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput); +} + +void Log::Widget::appendToLastLine(const QString &text) +{ + logExtra(text); + uint p = paragraphs() - 1; + insertAt(escapeXml(text), p, paragraphLength(p)); + updateContents(); // #### fix bug in Qt (display is messed up) + ensureVisible(0, contentsHeight()); + // immediately visible... + QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput); +} + +QPopupMenu *Log::Widget::createPopupMenu(const QPoint &pos) +{ + updateDebugLevel(); + _popup = QTextEdit::createPopupMenu(pos); + KIconLoader loader; + QIconSet iset = loader.loadIconSet("filesave", KIcon::Small, 0); + _popup->insertItem(iset, "Save As...", this, SLOT(saveAs())); + iset = loader.loadIconSet("fileclose", KIcon::Small, 0); + _popup->insertItem(iset, "Clear", this, SLOT(clear())); + _popup->insertSeparator(); + FOR_EACH(DebugLevel, level) { + _id[level.type()] = _popup->insertItem(level.label()); + _popup->setItemChecked(_id[level.type()], _debugLevel==level); + } + _popup->insertSeparator(); + int id = _popup->insertItem(i18n("Output in console"), this, SLOT(toggleConsoleOutput())); + _popup->setItemChecked(id, GlobalConfig::logOutputType()==GuiConsole); + connect(_popup, SIGNAL(activated(int)), SLOT(toggleVisible(int))); + return _popup; +} + +void Log::Widget::toggleVisible(int id) +{ + FOR_EACH(DebugLevel, level) { + if ( _id[level.type()]==id ) { + _debugLevel = level; + GlobalConfig::writeDebugLevel(level); + break; + } + } +} + +void Log::Widget::toggleConsoleOutput() +{ + GlobalConfig::writeLogOutputType(GlobalConfig::logOutputType()==GuiOnly ? GuiConsole : GuiOnly); +} + +void Log::Widget::sorry(const QString &message, const QString &details) +{ + logExtra(message + " [" + details + "]\n"); + MessageBox::detailedSorry(message, details, Log::Show); +} + +bool Log::Widget::askContinue(const QString &message) +{ + bool ok = MessageBox::askContinue(message); + logExtra(message + " [" + (ok ? "continue" : "cancel") + "]\n"); + return ok; +} + +void Log::Widget::clear() +{ + QTextEdit::clear(); + _text = QString::null; +} + +void Log::Widget::saveAs() +{ + PURL::Url url = PURL::getSaveUrl(":save_log", "text/x-log", this, i18n("Save log to file"), PURL::AskOverwrite); + if ( url.isEmpty() ) return; + url.write(_text, *this); +} diff --git a/src/libgui/log_view.h b/src/libgui/log_view.h new file mode 100644 index 0000000..c84849e --- /dev/null +++ b/src/libgui/log_view.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef LOG_VIEW_H +#define LOG_VIEW_H + +#include <qtextedit.h> +#include "common/global/log.h" + +namespace Log +{ +enum OutputType { GuiOnly = 0, GuiConsole, Nb_OutputTypes }; + +class Widget : public QTextEdit, public View +{ + Q_OBJECT +public: + Widget(QWidget *parent = 0, const char *name = 0); + virtual void appendToLastLine(const QString &text); + virtual void clear(); + virtual void sorry(const QString &message, const QString &details); + virtual bool askContinue(const QString &message); + +protected: + QPopupMenu *createPopupMenu(const QPoint &pos); + +private slots: + void toggleVisible(int i); + void toggleConsoleOutput(); + void saveAs(); + +private: + int _id[DebugLevel::Nb_Types]; + QPopupMenu *_popup; + QString _text; + + virtual void updateDebugLevel(); + virtual void doLog(LineType type, const QString &text, Action action = Immediate); + virtual void doLog(DebugLevel level, const QString &text, Action action = Immediate); + void doLog(const QString &text, const QString &color, bool bold, Action action = Immediate); + void logExtra(const QString &text); +}; + +} // namespace + +#endif diff --git a/src/libgui/main_global.cpp b/src/libgui/main_global.cpp new file mode 100644 index 0000000..8741a44 --- /dev/null +++ b/src/libgui/main_global.cpp @@ -0,0 +1,81 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "main_global.h" + +#include <qpopupmenu.h> + +#include "toplevel.h" +#include "common/global/about.h" +#include "global_config.h" +#include "devices/list/device_list.h" +#include "project_manager.h" +#include "editor_manager.h" +#include "tools/list/compile_config.h" +#include "gui_prog_manager.h" +#include "device_editor.h" + +Main::State Main::_state = Main::Idle; +MainWindow *Main::_toplevel = 0; +EditorManager *Main::_editorManager = 0; +ProjectManager::View *Main::_projectManager = 0; +Breakpoint::View *Main::_breakpointsView = 0; +Register::WatchView *Main::_watchView = 0; +Compile::LogWidget *Main::_compileLog = 0; +Compile::Manager *Main::_compileManager = 0; +ConsoleView *Main::_consoleView = 0; + +void Main::setState(State state) +{ + _state = state; + _toplevel->updateGUI(); +} + +Programmer::Base *Main::programmer() +{ + return Programmer::manager->programmer(); +} + +const Programmer::Group &Main::programmerGroup() +{ + return GlobalConfig::programmerGroup(); +} + +Programmer::State Main::programmerState() +{ + return (programmer() ? programmer()->state() : Programmer::NotConnected); +} + +KAction *Main::action(const char* name) +{ + return _toplevel->KMainWindow::action(name); +} +KAction *Main::action(KStdAction::StdAction action) +{ + return _toplevel->KMainWindow::action(KStdAction::name(action)); +} + +QPopupMenu &Main::popup(const char *name) +{ + QPopupMenu *popup = static_cast<QPopupMenu *>(_toplevel->factory()->container(name, _toplevel)); + Q_ASSERT(popup); + return *popup; +} + +const Device::Data *Main::deviceData() +{ + QString name = device(); + if ( name==Device::AUTO_DATA.name ) + name = DeviceEditor::guessDeviceFromFile(_projectManager->projectUrl()); + return Device::lister().data(name); +} + +Editor *Main::currentEditor() { return _editorManager->currentEditor(); } +Project *Main::project() { return _projectManager->project(); } +QString Main::device() { return Compile::Config::device(project()); } +const Tool::Group &Main::toolGroup() { return Compile::Config::toolGroup(project()); } diff --git a/src/libgui/main_global.h b/src/libgui/main_global.h new file mode 100644 index 0000000..020253e --- /dev/null +++ b/src/libgui/main_global.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef MAIN_GLOBAL_H +#define MAIN_GLOBAL_H + +#include <qstring.h> +#include <qpopupmenu.h> +#include <kstdaction.h> + +#include "progs/base/generic_prog.h" + +class EditorManager; +namespace ProjectManager { class View; } +class Editor; +class Project; +namespace Compile { class LogWidget; class Manager; } +namespace Register { class List; class WatchView; } +namespace Breakpoint { class View; } +class MainWindow; +namespace Programmer { class Group; class Base; } +namespace Device { class Data; } +namespace Tool { class Group; } +class ConsoleView; + +class Main +{ +public: + enum State { Idle, Compiling, Programming, Closing }; + static void setState(State state); + static State state() { return _state; } + + static MainWindow &toplevel() { return *_toplevel; } + static const Programmer::Group &programmerGroup(); + static Programmer::Base *programmer(); + static Programmer::State programmerState(); + static KAction *action(const char *name); + static KAction *action(KStdAction::StdAction action); + static QPopupMenu &popup(const char *name); + static EditorManager &editorManager() { return *_editorManager; } + static Editor *currentEditor(); + static QString device(); + static const Device::Data *deviceData(); + static Breakpoint::View &breakpointsView() { return *_breakpointsView; } + static ProjectManager::View &projectManager() { return *_projectManager; } + static Project *project(); + static Register::WatchView &watchView() { return *_watchView; } + static Compile::LogWidget &compileLog() { return *_compileLog; } + static const Tool::Group &toolGroup(); + +private: + static State _state; + static MainWindow *_toplevel; + static EditorManager *_editorManager; + static ProjectManager::View *_projectManager; + static Breakpoint::View *_breakpointsView; + static Register::WatchView *_watchView; + static Compile::LogWidget *_compileLog; + static Compile::Manager *_compileManager; + static ConsoleView *_consoleView; + + friend class MainWindow; +}; + +#endif diff --git a/src/libgui/new_dialogs.cpp b/src/libgui/new_dialogs.cpp new file mode 100644 index 0000000..d26c15c --- /dev/null +++ b/src/libgui/new_dialogs.cpp @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "new_dialogs.h" + +#include <klocale.h> +#include <kiconloader.h> +#include <kpushbutton.h> + +#include "common/gui/purl_gui.h" +#include "project.h" + +//---------------------------------------------------------------------------- +NewDialog::NewDialog(const QString &caption, QWidget *parent) + : Dialog(parent, "new_dialog", true, caption, Ok|Cancel, Ok, false) +{ + _top = new QGridLayout(mainWidget(), 0, 0, 10, 10); + _top->setColStretch(2, 1); + + _fLabel = new QLabel(mainWidget()); + _top->addWidget(_fLabel, 0, 0); + _filename = new QLineEdit(mainWidget()); + connect(_filename, SIGNAL(textChanged(const QString &)), SLOT(changed())); + _top->addMultiCellWidget(_filename, 0,0, 1,3); + + QLabel *label= new QLabel(i18n("Location:"), mainWidget()); + _top->addWidget(label, 1, 0); + _dir = new QLineEdit(mainWidget()); + connect(_dir, SIGNAL(textChanged(const QString &)), SLOT(changed())); + _top->addMultiCellWidget(_dir, 1,1, 1,2); + KIconLoader loader; + QIconSet iconset = loader.loadIcon("fileopen", KIcon::Toolbar); + KPushButton *button = new KPushButton(iconset, QString::null, mainWidget()); + connect(button, SIGNAL(clicked()), SLOT(browse())); + _top->addWidget(button, 1, 3); + + _filename->setFocus(); + enableButtonOK(false); +} + +void NewDialog::changed() +{ + enableButtonOK(!_filename->text().isEmpty() && !_dir->text().isEmpty()); +} + +void NewDialog::browse() +{ + PURL::Directory dir = PURL::getExistingDirectory(startDir(), this, QString::null); + if ( dir.isEmpty() ) return; + _dir->setText(dir.path()); +} + +//---------------------------------------------------------------------------- +NewFileDialog::NewFileDialog(Project *project, QWidget *parent) + : NewDialog(i18n("Create New File"), parent), _project(project) +{ + _fLabel->setText(i18n("File Name:")); + + if (project) { + _add = new QCheckBox(i18n("Add to project"), mainWidget()); + _add->setChecked(project); + _top->addMultiCellWidget(_add, 2,2, 1,2); + _top->setRowStretch(3, 1); + _dir->setText(project->directory().path()); + } +} + +QString NewFileDialog::startDir() const +{ + if (_project) return _project->directory().path(); + return ":new_file"; +} + +PURL::Url NewFileDialog::url() const +{ + return PURL::Url(PURL::Directory(_dir->text()), _filename->text()); +} diff --git a/src/libgui/new_dialogs.h b/src/libgui/new_dialogs.h new file mode 100644 index 0000000..26e3cf7 --- /dev/null +++ b/src/libgui/new_dialogs.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef NEW_DIALOGS_H +#define NEW_DIALOGS_H + +#include <qlineedit.h> +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <kcombobox.h> + +#include "common/global/purl.h" +#include "common/gui/dialog.h" +class Project; + +//---------------------------------------------------------------------------- +class NewDialog : public Dialog +{ +Q_OBJECT +public: + NewDialog(const QString &caption, QWidget *parent); + +protected: + QGridLayout *_top; + QLabel *_fLabel; + QLineEdit *_filename, *_dir; + + virtual QString startDir() const = 0; + +private slots: + void changed(); + void browse(); +}; + +//---------------------------------------------------------------------------- +class NewFileDialog : public NewDialog +{ +Q_OBJECT +public: + NewFileDialog(Project *project, QWidget *parent); + PURL::Url url() const; + bool addToProject() const { return (_project ? _add->isChecked() : false); } + +private: + Project *_project; + QCheckBox *_add; + + virtual QString startDir() const; +}; + +#endif diff --git a/src/libgui/object_view.cpp b/src/libgui/object_view.cpp new file mode 100644 index 0000000..91625fb --- /dev/null +++ b/src/libgui/object_view.cpp @@ -0,0 +1,145 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "object_view.h" + +#include <klocale.h> + +#include "devices/base/device_group.h" +#include "devices/pic/pic/pic_memory.h" +#include "tools/gputils/gputils.h" +#include "hex_editor.h" +#include "coff/base/text_coff.h" +#include "coff/base/coff_archive.h" +#include "main_global.h" +#include "tools/list/compile_process.h" +#include "coff/base/disassembler.h" +#include "common/gui/misc_gui.h" + +//----------------------------------------------------------------------------- +Coff::BaseEditor::BaseEditor(const PURL::Url &source, const Device::Data *data, QWidget *parent) + : SimpleTextEditor(true, parent), _source(source), _ok(false), _created(0), _device(data) +{ + setReadOnly(true); + _view->setDynWordWrap(false); + setView(&Main::compileLog()); +} + +Coff::BaseEditor::~BaseEditor() +{ + delete _created; +} + +//----------------------------------------------------------------------------- +Coff::CoffEditor::CoffEditor(const PURL::Url &source, const Device::Data &data, QWidget *parent) + : BaseEditor(source, &data, parent), _provided(0) +{} + +Coff::CoffEditor::CoffEditor(const TextObject &object, QWidget *parent) + : BaseEditor(PURL::Url(), object.device(), parent), _provided(&object) +{} + +bool Coff::CoffEditor::open(const PURL::Url &url) +{ + _url = url; + if (_provided) return setText(_provided->disassembly()); + if ( _created==0 ) { + _created = new TextObject(_device, _source); + _ok = _created->parse(*this); + } + return setText(static_cast<Coff::TextObject *>(_created)->disassembly()); +} + +//----------------------------------------------------------------------------- +Coff::ObjectEditor::ObjectEditor(const PURL::Url &source, QWidget *parent) + : BaseEditor(source, 0, parent) +{} + +bool Coff::ObjectEditor::open(const PURL::Url &url) +{ + _url = url; + if ( _created==0 ) { + _created = new TextObject(0, _source); + _ok = _created->parse(*this); + } + if ( !_ok ) return setText(i18n("Error parsing object:\n") + error()); + QString s = coff()->information().text() + "\n"; + return setText(s); +} + +//----------------------------------------------------------------------------- +Coff::LibraryEditor::LibraryEditor(const PURL::Url &source, QWidget *parent) + : BaseEditor(source, 0, parent) +{} + +bool Coff::LibraryEditor::open(const PURL::Url &url) +{ + _url = url; + if ( _created==0 ) { + _created = new Archive(_source); + _ok = _created->parse(*this); + } + if ( !_ok ) return setText(i18n("Error parsing library:\n") + error()); + QString s = coff()->information().text() + "\n"; + if ( coff()->members().count()!=0 ) s += coff()->membersInformation().text() + "\n"; + if ( coff()->symbols().count()!=0 ) s += coff()->symbolsInformation().text() + "\n"; + return setText(s); +} + +//----------------------------------------------------------------------------- +DisassemblyEditor::DisassemblyEditor(const PURL::Url &source, const Device::Data &data, QWidget *parent) + : SimpleTextEditor(true, parent), _source(source), _device(data), _editor(0) +{ + setReadOnly(true); + _view->setDynWordWrap(false); + setView(&Main::compileLog()); +} + +DisassemblyEditor::DisassemblyEditor(const HexEditor &e, const Device::Data &data, QWidget *parent) + : SimpleTextEditor(true, parent), _device(data), _editor(&e) +{ + setReadOnly(true); + _view->setDynWordWrap(false); + setView(&Main::compileLog()); +} + +bool DisassemblyEditor::open(const PURL::Url &url) +{ + _url = url; + if ( Main::toolGroup().name()!="sdcc" && Main::toolGroup().name()!="gputils" ) { + MessageBox::sorry(i18n("Disassembly not supported for the selected toolchain."), Log::Show); + return false; + } + Pic::Architecture arch = (_device.group().name()=="pic" ? static_cast<const Pic::Data &>(_device).architecture() : Pic::Architecture(Pic::Architecture::Nb_Types)); + if ( arch==Pic::Architecture::Nb_Types ) { + MessageBox::sorry(i18n("Disassembly not supported for the selected device."), Log::Show); + return false; + } + + Device::Memory *memory = 0; + if ( _editor==0 ) { + log(Log::LineType::Information, i18n("Disassembling hex file: %1").arg(_source.pretty())); + PURL::File file(_source, Main::compileLog()); + if ( !file.openForRead() ) return false; + memory = _device.group().createMemory(_device); + QStringList errors, warnings; + Device::Memory::WarningTypes warningTypes; + if ( !memory->load(file.stream(), errors, warningTypes, warnings) ) { + delete memory; + log(Log::LineType::Error, errors[0]); + return false; + } + for (uint i=0; i<warnings.count(); i++) log(Log::LineType::Warning, warnings[i]); + } else { + log(Log::LineType::Information, i18n("Disassembling content of hex file editor.")); + memory = const_cast<Device::Memory *>(_editor->memory()); + } + SourceLine::List list = GPUtils::disassemble(static_cast<const Pic::Memory &>(*memory)); + if ( _editor==0 ) delete memory; + return setText(SourceLine::text(PURL::SourceFamily::Asm, list, 4)); +} diff --git a/src/libgui/object_view.h b/src/libgui/object_view.h new file mode 100644 index 0000000..358101b --- /dev/null +++ b/src/libgui/object_view.h @@ -0,0 +1,99 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef OBJECT_VIEW_H +#define OBJECT_VIEW_H + +#include "text_editor.h" +#include "coff/base/coff_archive.h" +#include "coff/base/coff_object.h" +namespace Device { class Data; } +class HexEditor; + +namespace Coff +{ +class Base; +class TextObject; + +//----------------------------------------------------------------------------- +class BaseEditor : public SimpleTextEditor, public Log::Base +{ +Q_OBJECT +public: + BaseEditor(const PURL::Url &source, const Device::Data *data, QWidget *parent); + virtual ~BaseEditor(); + virtual PURL::Url url() const { return _url; } + +protected: + PURL::Url _source, _url; + bool _ok; + Coff::Base *_created; + const Device::Data *_device; +}; + +//----------------------------------------------------------------------------- +class CoffEditor : public BaseEditor +{ +Q_OBJECT +public: + CoffEditor(const PURL::Url &source, const Device::Data &data, QWidget *parent); + CoffEditor(const TextObject &object, QWidget *parent); + virtual PURL::FileType fileType() const { return PURL::Coff; } + virtual bool open(const PURL::Url &url); + +private: + const TextObject *_provided; +}; + +//----------------------------------------------------------------------------- +class ObjectEditor : public BaseEditor +{ +Q_OBJECT +public: + ObjectEditor(const PURL::Url &source, QWidget *parent); + virtual PURL::FileType fileType() const { return PURL::Unknown; } + virtual bool open(const PURL::Url &url); + +private: + const Coff::Object *coff() const { return static_cast<const Coff::Object *>(_created); } +}; + +//----------------------------------------------------------------------------- +class LibraryEditor : public BaseEditor +{ +Q_OBJECT +public: + LibraryEditor(const PURL::Url &source, QWidget *parent); + virtual PURL::FileType fileType() const { return PURL::Unknown; } + virtual bool open(const PURL::Url &url); + +private: + const Coff::Archive *coff() const { return static_cast<const Coff::Archive *>(_created); } +}; + +} // namespace + +//----------------------------------------------------------------------------- +class DisassemblyEditor : public SimpleTextEditor, public Log::Base +{ +Q_OBJECT +public: + DisassemblyEditor(const PURL::Url &hexUrl, const Device::Data &data, QWidget *parent); + DisassemblyEditor(const HexEditor &e, const Device::Data &data, QWidget *parent); + virtual PURL::FileType fileType() const { return PURL::AsmGPAsm; } + virtual bool open(const PURL::Url &url); + virtual PURL::Url url() const { return _url; } + +private: + PURL::Url _source, _url; + const Device::Data &_device; + const HexEditor *_editor; +}; + + +#endif diff --git a/src/libgui/project.cpp b/src/libgui/project.cpp new file mode 100644 index 0000000..dcf34c3 --- /dev/null +++ b/src/libgui/project.cpp @@ -0,0 +1,226 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "project.h" + +#include <ksimpleconfig.h> + +#include "devices/list/device_list.h" +#include "progs/base/prog_group.h" +#include "global_config.h" +#include "tools/gputils/gputils_config.h" + +bool Project::load(QString &error) +{ + if ( _url.fileType()==PURL::Project ) return XmlDataFile::load(error); + + if ( !_url.exists() ) { + error = i18n("Project file %1 does not exist.").arg(_url.pretty()); + return false; + } + PURL::Url tmp = _url; + _url = _url.toFileType(PURL::Project); + if ( _url.exists() && XmlDataFile::load(error) ) return true; + KConfig *config = new KSimpleConfig(tmp.filepath(), false); + + config->setGroup("Files"); + QStringList list = config->readListEntry("inputFiles"); + QStringList::const_iterator it = list.begin(); + for (; it!=list.end(); ++it) addFile(PURL::Url(directory(), *it)); + + config->setGroup("General"); + setVersion(config->readEntry("version", "0.1")); + setDescription(config->readEntry("description", QString::null)); + + config->setGroup("Assembler"); + QString device = config->readEntry("target-device"); + if ( device=="*" ) device = GlobalConfig::programmerGroup().supportedDevices()[0]; // compatibility + Compile::Config::setDevice(this, Device::lister().checkName(device)); + GPUtils::Config *gconfig = new GPUtils::Config(this); + gconfig->setGPAsmWarningLevel(QMIN(config->readUnsignedNumEntry("warn-level", 0), uint(GPUtils::Config::Nb_WarningLevels))); + gconfig->setRawIncludeDirs(Tool::Category::Assembler, config->readEntry("include-dir", QString::null)); + gconfig->setRawCustomOptions(Tool::Category::Assembler, config->readEntry("other-options", QString::null)); + + config->setGroup("Linker") ; + QString hexFormatString = config->readEntry("hex-format", HexBuffer::FORMATS[HexBuffer::IHX32]); + for (uint i=0; i<HexBuffer::Nb_Formats; i++) + if ( hexFormatString==HexBuffer::FORMATS[i] ) gconfig->setHexFormat(HexBuffer::Format(i)); + gconfig->setRawIncludeDirs(Tool::Category::Linker, config->readEntry("objs-libs-dir", QString::null)); + gconfig->setRawCustomOptions(Tool::Category::Linker, config->readEntry("other-options", QString::null)); + + delete gconfig; + delete config; + return true; +} + +PURL::UrlList Project::openedFiles() const +{ + PURL::UrlList files; + QStringList list = listValues("general", "opened_files", QStringList()); + QStringList::const_iterator it = list.begin(); + for (; it!=list.end(); ++it) { + if ( PURL::Url::fromPathOrUrl(*it).isRelative() ) files += PURL::Url(directory(), *it); + else files += PURL::Url::fromPathOrUrl(*it); + } + return files; +} +void Project::setOpenedFiles(const PURL::UrlList &list) +{ + clearList("general", "opened_files"); + PURL::UrlList::const_iterator it = list.begin(); + for (; it!=list.end(); ++it) + appendListValue("general", "opened_files", (*it).relativeTo(directory())); +} + +PURL::UrlList Project::absoluteFiles() const +{ + PURL::UrlList abs; + QStringList files = listValues("general", "files", QStringList()); + QStringList::const_iterator it = files.begin(); + for (; it!=files.end(); ++it) abs += PURL::Url::fromPathOrUrl(*it).toAbsolute(directory()); + return abs; +} +void Project::addFile(const PURL::Url &url) +{ + appendListValue("general", "files", url.relativeTo(directory())); +} +void Project::removeFile(const PURL::Url &url) +{ + removeListValue("general", "files", url.relativeTo(directory())); +} +void Project::clearFiles() +{ + clearList("general", "files"); +} + +QString Project::toSourceObject(const PURL::Url &url, const QString &extension, bool forWindows) const +{ + PURL::Url tmp; + if ( extension.isEmpty() ) tmp = url.toFileType(PURL::Object); + else tmp = url.toExtension(extension); + return tmp.relativeTo(directory(), forWindows ? PURL::WindowsSeparator : PURL::UnixSeparator); +} + +QStringList Project::objectsForLinker(const QString &extension, bool forWindows) const +{ + QStringList objs; + // objects files corresponding to src files + PURL::UrlList files = absoluteFiles(); + PURL::UrlList::const_iterator it; + for (it=files.begin(); it!=files.end(); ++it) + if ( (*it).data().group==PURL::Source ) objs += toSourceObject(*it, extension, forWindows); + // objects + for (it=files.begin(); it!=files.end(); ++it) + if ( (*it).fileType()==PURL::Object ) objs += (*it).relativeTo(directory(), forWindows ? PURL::WindowsSeparator : PURL::UnixSeparator); + return objs; +} + +QStringList Project::librariesForLinker(const QString &prefix, bool forWindows) const +{ + QStringList libs; + PURL::UrlList files = absoluteFiles(); + PURL::UrlList::const_iterator it; + for (it=files.begin(); it!=files.end(); ++it) + if ( (*it).fileType()==PURL::Library ) libs += prefix + (*it).relativeTo(directory(), forWindows ? PURL::WindowsSeparator : PURL::UnixSeparator); + return libs; +} + +QString Project::version() const +{ + return Compile::Config::globalValue(this, "version", "0.1"); +} +void Project::setVersion(const QString &version) +{ + Compile::Config::setGlobalValue(this, "version", version); +} + +Tool::OutputType Project::outputType() const +{ + return Tool::OutputType::fromKey(Compile::Config::globalValue(this, "output_type", Tool::OutputType(Tool::OutputType::Executable).key())); +} +void Project::setOutputType(Tool::OutputType type) +{ + Compile::Config::setGlobalValue(this, "output_type", type.key()); +} + +QString Project::description() const +{ + return Compile::Config::globalValue(this, "description", QString::null); +} +void Project::setDescription(const QString &description) +{ + Compile::Config::setGlobalValue(this, "description", description); +} + +PURL::Url Project::customLinkerScript() const +{ + QString s = Compile::Config::globalValue(this, "custom_linker_script", QString::null); + return PURL::Url::fromPathOrUrl(s); +} +void Project::setCustomLinkerScript(const PURL::Url &url) +{ + Compile::Config::setGlobalValue(this, "custom_linker_script", url.filepath()); +} + +QValueList<Register::TypeData> Project::watchedRegisters() const +{ + QValueList<Register::TypeData> watched; + QStringList list = listValues("general", "watched_registers", QStringList()); + QStringList::const_iterator it; + for (it=list.begin(); it!=list.end(); ++it) { + Register::TypeData rtd = Register::TypeData::fromString(*it); + if ( rtd.type()!=Register::Invalid ) watched.append(rtd); + } + return watched; +} +void Project::setWatchedRegisters(const QValueList<Register::TypeData> &watched) +{ + clearList("general", "watched_registers"); + QValueList<Register::TypeData>::const_iterator it; + for (it=watched.begin(); it!=watched.end(); ++it) + appendListValue("general", "watched_registers", (*it).toString()); +} + +QValueList<uint> Project::bookmarkLines(const PURL::Url &url) const +{ + QValueList<uint> lines; + QStringList list = listValues("editors", "bookmarks", QStringList()); + QStringList::const_iterator it; + for (it=list.begin(); it!=list.end(); ++it) { + QStringList slist = QStringList::split(",", *it); + QStringList::const_iterator sit = slist.begin(); + if ( sit==slist.end() || (*sit)!=url.kurl().url() ) continue; + for (; sit!=slist.end(); ++sit) { + bool ok; + uint line = (*sit).toUInt(&ok); + if (!ok) continue; + lines.append(line); + } + break; + } + return lines; +} +void Project::setBookmarkLines(const PURL::Url &url, const QValueList<uint> &lines) +{ + QStringList list = listValues("editors", "bookmarks", QStringList()); + QStringList nlist; + QStringList::const_iterator it; + for (it=list.begin(); it!=list.end(); ++it) { + QStringList slist = QStringList::split(",", *it); + QStringList::const_iterator sit = slist.begin(); + if ( sit!=slist.end() && slist.count()>1 && (*sit)!=url.kurl().url() ) nlist += *it; + } + if ( lines.count()!=0 ) { + QStringList slist = url.kurl().url(); + QValueList<uint>::const_iterator lit; + for (lit=lines.begin(); lit!=lines.end(); ++lit) slist += QString::number(*lit); + nlist += slist.join(","); + } + setListValues("editors", "bookmarks", nlist); +} diff --git a/src/libgui/project.h b/src/libgui/project.h new file mode 100644 index 0000000..0dfdeab --- /dev/null +++ b/src/libgui/project.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef PROJECT_H +#define PROJECT_H + +#include "devices/base/register.h" +#include "common/global/xml_data_file.h" +#include "tools/base/generic_tool.h" + +class Project : public XmlDataFile +{ +public: + Project(const PURL::Url &url) : XmlDataFile(url, "piklab") {} + virtual bool load(QString &error); + + PURL::Directory directory() const { return url().directory(); } + QString name() const { return url().basename(); } + PURL::UrlList absoluteFiles() const; + QString version() const; + QString description() const; + Tool::OutputType outputType() const; + PURL::UrlList openedFiles() const; + PURL::Url customLinkerScript() const; + QValueList<Register::TypeData> watchedRegisters() const; + QString toSourceObject(const PURL::Url &url, const QString &extension, bool forWindows) const; + QStringList objectsForLinker(const QString &extension, bool forWindows) const; + QStringList librariesForLinker(const QString &prefix, bool forWindows) const; + QValueList<uint> bookmarkLines(const PURL::Url &url) const; // absolute filepath + + void removeFile(const PURL::Url &url); // take absolute filepath (but inside project dir) + void addFile(const PURL::Url &url); // take absolute filePath (but inside project dir) + void clearFiles(); + void setVersion(const QString &version); + void setDescription(const QString &description); + void setOutputType(Tool::OutputType type); + void setOpenedFiles(const PURL::UrlList &list); + void setCustomLinkerScript(const PURL::Url &url); + void setWatchedRegisters(const QValueList<Register::TypeData> &watched); + void setBookmarkLines(const PURL::Url &url, const QValueList<uint> &lines); // absolute filepath +}; + +#endif diff --git a/src/libgui/project_editor.cpp b/src/libgui/project_editor.cpp new file mode 100644 index 0000000..4b86429 --- /dev/null +++ b/src/libgui/project_editor.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "project_editor.h" + +#include <qlabel.h> +#include <qlayout.h> +#include <klocale.h> + +#include "project.h" +#include "tools/list/compile_config.h" +#include "device_gui.h" + +ProjectEditor::ProjectEditor(Project &project, QWidget *parent) + : Dialog(parent, "project_options", true, i18n("Project Options"), Ok|Cancel, Ok, false), + _project(project) +{ + QVBoxLayout *top = new QVBoxLayout(mainWidget(), 0, 10); + TabWidget *tabWidget = new TabWidget(mainWidget()); + top->addWidget(tabWidget); + +// global + QWidget *tab = new QWidget(tabWidget); + tabWidget->addTab(tab, i18n("General")); + QGridLayout *grid = new QGridLayout(tab, 0, 0, 10, 10); + QLabel *label = new QLabel(i18n("Name:"), tab); + grid->addWidget(label, 0, 0); + label = new QLabel(project.name(), tab); + grid->addWidget(label, 0, 1); + label = new QLabel(i18n("Description:"), tab); + grid->addWidget(label, 1, 0); + _description = new QTextEdit(tab); + _description->setText(_project.description()); + grid->addMultiCellWidget(_description, 1,1, 1,2); + label = new QLabel(i18n("Version:"), tab); + grid->addWidget(label, 2, 0); + _version = new QLineEdit(tab); + _version->setText(_project.version()); + grid->addWidget(_version, 2, 1); + label = new QLabel(i18n("Device:"), tab); + grid->addWidget(label, 3, 0); + _device = new DeviceChooser::Button(false, tab); + _device->setDevice(Compile::Config::device(&_project)); + grid->addWidget(_device, 3, 1); + grid->setRowStretch(4, 1); + grid->setColStretch(2, 1); + +// toochain + tab = new QWidget(tabWidget); + tabWidget->addTab(tab, i18n("Toochain")); + grid = new QGridLayout(tab, 0, 0, 10, 10); + _tools = new ToolsConfigWidget(&project, tab); + _tools->loadConfig(); + grid->addMultiCellWidget(_tools, 0,0, 0,2); + grid->setRowStretch(1, 1); + grid->setColStretch(2, 1); +} + +void ProjectEditor::slotOk() +{ + _project.setDescription(_description->text()); + _project.setVersion(_version->text()); + Compile::Config::setDevice(&_project, _device->device()); + _tools->saveConfig(); + accept(); +} diff --git a/src/libgui/project_editor.h b/src/libgui/project_editor.h new file mode 100644 index 0000000..5e83fe2 --- /dev/null +++ b/src/libgui/project_editor.h @@ -0,0 +1,47 @@ +/*************************************************************************** + ProjectEditorWid.cpp - description + ------------------- + begin : lun déc 8 2003 + copyright : (C) 2003 by Alain Gibaud + email : alain.gibaud@univ-valenciennes.fr + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifndef PROJECT_EDITOR_H +#define PROJECT_EDITOR_H + +#include <qtextedit.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <qwidgetstack.h> + +#include "tools/list/tools_config_widget.h" +#include "common/gui/misc_gui.h" +class Project; +namespace DeviceChooser { class Button; } + +class ProjectEditor : public Dialog +{ +Q_OBJECT +public: + ProjectEditor(Project &project, QWidget *parent); + +private slots: + virtual void slotOk(); + +private: + Project &_project; + QTextEdit *_description; + QLineEdit *_version; + DeviceChooser::Button *_device; + ToolsConfigWidget *_tools; +}; + +#endif diff --git a/src/libgui/project_manager.cpp b/src/libgui/project_manager.cpp new file mode 100644 index 0000000..dcc4941 --- /dev/null +++ b/src/libgui/project_manager.cpp @@ -0,0 +1,651 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "project_manager.h" + +#include <qdragobject.h> +#include <qpainter.h> +#include <qstyle.h> +#include <qtimer.h> +#include <qheader.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <kaction.h> +#include <kapplication.h> + +#include "project.h" +#include "project_wizard.h" +#include "project_editor.h" +#include "toplevel.h" +#include "editor_manager.h" +#include "object_view.h" +#include "devices/list/device_list.h" +#include "tools/list/compile_config.h" +#include "register_view.h" +#include "hex_editor.h" +#include "main_global.h" +#include "common/gui/purl_gui.h" +#include "device_gui.h" + +//---------------------------------------------------------------------------- +ProjectManager::View::View(QWidget *parent) + : ListView(parent, "project_manager"), _project(0), _modified(false) +{ + connect(this, SIGNAL(mouseButtonClicked(int, QListViewItem *, const QPoint &, int)), + SLOT(clicked(int, QListViewItem *, const QPoint &, int))); + connect(this, SIGNAL(contextMenuRequested(QListViewItem *, const QPoint &, int)), + SLOT(contextMenu(QListViewItem *, const QPoint &, int))); + connect(this, SIGNAL(itemRenamed(QListViewItem *, int, const QString &)), + SLOT(renamed(QListViewItem *, int, const QString &))); + connect(this, SIGNAL(moved()), SLOT(filesReordered())); + + header()->hide(); + setSorting(-1); + addColumn(QString::null, 170); + setFullWidth(true); + setRootIsDecorated(false); + setAcceptDrops(true); + setDragEnabled(true); + setDropVisualizer(true); + QTimer::singleShot(0, this, SLOT(init()));; +} + +ProjectManager::View::~View() +{ + delete _project; +} + +void ProjectManager::View::init() +{ + clear(); + _rootItem = new RootItem(this); + setCurrentItem(_rootItem); + KListViewItem *item = new RegisterItem(headerItem(DeviceGroup)); + ensureItemVisible(item); + _deviceItem = new DeviceItem(headerItem(DeviceGroup)); + ensureItemVisible(_deviceItem); + _linkerScriptItem = 0; + (void)headerItem(SourceGroup); +} + +ProjectManager::HeaderItem *ProjectManager::View::findHeaderItem(Group group) const +{ + QListViewItemIterator it(const_cast<View *>(this)); + for(; it.current(); ++it) { + if ( it.current()->rtti()!=HeaderRtti ) continue; + HeaderItem *hi = static_cast<HeaderItem *>(it.current()); + if ( hi->group()==group ) return hi; + } + return 0; +} + +ProjectManager::HeaderItem *ProjectManager::View::headerItem(Group group) +{ + HeaderItem *item = findHeaderItem(group); + if (item) return item; + item = new HeaderItem(_rootItem, group); + // reorder groups... + HeaderItem *items[Nb_Groups]; + for (uint i=0; i<Nb_Groups; i++) { + items[i] = findHeaderItem(Group(i)); + if (items[i]) _rootItem->takeItem(items[i]); + } + for (int i=Nb_Groups-1; i>=0; i--) { + if ( items[i]==0 ) continue; + _rootItem->insertItem(items[i]); + } + return item; +} + +ProjectManager::FileItem *ProjectManager::View::findFileItem(const PURL::Url &url) const +{ + QListViewItemIterator it(const_cast<View *>(this)); + for(; it.current(); ++it) { + if ( it.current()->rtti()!=FileRtti ) continue; + FileItem *fi = static_cast<FileItem *>(it.current()); + if ( fi->url()==url ) return fi; + } + return 0; +} + +ProjectManager::FileItem *ProjectManager::View::findFileItem(PURL::FileType type) const +{ + QListViewItemIterator it(const_cast<View *>(this)); + for(; it.current(); ++it) { + if ( it.current()->rtti()!=FileRtti ) continue; + FileItem *fi = static_cast<FileItem *>(it.current()); + if ( fi->ftype()==type ) return fi; + } + return 0; +} + +QListViewItem *ProjectManager::View::findItem(const QString &tag) const +{ + QListViewItemIterator it(const_cast<View *>(this)); + for(; it.current(); ++it) { + switch (Rtti(it.current()->rtti())) { + case RootRtti: + case FileRtti: + case LinkerScriptRtti: + case DeviceRtti: continue; + case HeaderRtti: + case RegisterRtti: break; + } + if ( it.current()->text(0)==tag ) return it.current(); + } + return 0; +} + +void ProjectManager::View::select(const Editor *e) +{ + QListViewItem *item = 0; + if ( e->url().isEmpty() ) item = findItem(e->tag()); + else item = findFileItem(e->url()); + if (item) setSelected(item, true); + else clearSelection(); +} + +void ProjectManager::View::contextMenu(QListViewItem *item, const QPoint &p, int) +{ + if ( item==0 ) return; + + PopupMenu pop; + Group group = Nb_Groups; + if ( item->rtti()==HeaderRtti) group = static_cast<const HeaderItem *>(item)->group(); + + if ( item->rtti()==LinkerScriptRtti || group==LinkerScriptGroup ) { + if ( _project==0 || Main::toolGroup().linkerScriptType()==PURL::Nb_FileTypes ) return; + pop.insertTitle(i18n("Linker Script")); + pop.insertItem("piklab_addfile", i18n("Set Custom...")); + if ( !_project->customLinkerScript().isEmpty() ) pop.insertItem("editdelete", i18n("Set Default")); + switch( pop.exec(p) ) { + case 1: { + PURL::Url url = PURL::getOpenUrl(":custom_linker_script", PURL::filter(Main::toolGroup().linkerScriptType()), this, i18n("Select Linker Script")); + if ( !url.isEmpty() ) _project->setCustomLinkerScript(url); + break; + } + case 2: _project->setCustomLinkerScript(PURL::Url()); break; + } + _linkerScriptItem->init(); + } else if ( item->rtti()==RootRtti ) { + RootItem *ri = static_cast<RootItem *>(item); + if ( _project==0 ) { + if ( ri->url().isEmpty() ) { + pop.insertItem("piklab_createproject", i18n("New Project..."), &Main::toplevel(), SLOT(newProject())); + pop.insertItem("piklab_openproject", i18n("Open Project..."), &Main::toplevel(), SLOT(openProject())); + pop.exec(p); + } else { + pop.insertTitle(i18n("Standalone File")); + pop.insertItem("configure", i18n("Configure...")); + if ( pop.exec(p)==1 ) Main::toplevel().configure(ConfigCenter::Standalone); + } + } else { + pop.insertTitle(i18n("Project")); + pop.insertItem("configure", i18n("Options..."), &Main::toplevel(), SLOT(configureProject())); + pop.insertItem("find", i18n("Find Files..."), &Main::toplevel(), SLOT(runKfind())); + pop.insertSeparator(); + pop.insertItem("piklab_compile", i18n("Build Project"), &Main::toplevel(), SLOT(buildProject())); + pop.insertItem("trashcan_empty", i18n("Clean Project"), &Main::toplevel(), SLOT(cleanBuild())); + pop.insertSeparator(); + pop.insertItem("filenew", i18n("New Source File..."), &Main::toplevel(), SLOT(newSourceFile())); + pop.insertItem("piklab_addfile", i18n("Add Source Files..."), this, SLOT(insertSourceFiles())); + pop.insertItem("piklab_addfile", i18n("Add Object Files..."), this, SLOT(insertObjectFiles())); + if ( Main::currentEditor() ) pop.insertItem("piklab_addcurrentfile", i18n("Add Current File"), this, SLOT(insertCurrentFile())); + pop.exec(p); + } + } else if ( item->rtti()==FileRtti ) { + if ( _project==0 ) return; + FileItem *fi = static_cast<FileItem *>(item); + if ( isExternalFile(fi->url()) ) return; + pop.insertTitle(item->text(0)); + pop.insertItem("editdelete", i18n("Remove From Project")); + if ( pop.exec(p)==1 ) removeFile(fi->url()); + } else if ( item->rtti()==HeaderRtti ) { + if ( _project==0 ) return; + if ( group==LinkerObjectGroup ) { + pop.insertTitle(i18n("Objects")); + pop.insertItem("piklab_addfile", i18n("Add Object Files..."), this, SLOT(insertObjectFiles())); + pop.exec(p); + } else if ( group==SourceGroup || group==HeaderGroup ) { + pop.insertTitle(i18n("Sources")); + pop.insertItem("filenew", i18n("New File..."), &Main::toplevel(), SLOT(newSourceFile())); + pop.insertItem("piklab_addfile", i18n("Add Source Files..."), this, SLOT(insertSourceFiles())); + pop.exec(p); + } else if ( group==DeviceGroup ) { + pop.insertItem("filenew", i18n("Select Device..."), &Main::toplevel(), SLOT(showDeviceInfo())); + pop.exec(p); + } + } +} + +void ProjectManager::View::closeProject() +{ + if ( _project==0 && projectUrl().isEmpty() ) return; + if (_project) { + // save opened files + PURL::UrlList files = Main::editorManager().files(); + PURL::UrlList::const_iterator it = files.begin(); + PURL::UrlList opened; + for (; it!=files.end(); ++it) { + if ( !isExternalFile(*it) ) opened += *it; + Main::editorManager().closeEditor(*it); + } + _project->setOpenedFiles(opened); + // save watched registers + _project->setWatchedRegisters(Register::list().watched()); + QString error; + if ( !_project->save(error) ) + MessageBox::detailedSorry(i18n("Could not save project file \"%1\".").arg(_project->url().pretty()), error, Log::Show); + delete _project; + _project = 0; + } + _modified = false; + init(); +} + +void ProjectManager::View::addExternalFiles() +{ + const QMap<PURL::Url, FileOrigin> &ext = projectData().externals; + QMap<PURL::Url, FileOrigin>::const_iterator it; + for (it=ext.begin(); it!=ext.end(); ++it) { + if ( !it.key().exists() ) continue; + addFile(it.key(), it.key().fileType(), it.data()); + } +} + +void ProjectManager::View::setStandalone(const PURL::Url &url, PURL::FileType type) +{ + if ( projectUrl()==url ) return; + closeProject(); + _rootItem->set(url, true); + addFile(url, type, Intrinsic); + _standaloneData[url].type = type; + addExternalFiles(); +} + +PURL::Url ProjectManager::View::standaloneGenerator(const PURL::Url &url, PURL::FileType &type) const +{ + QMap<PURL::Url, ProjectData>::const_iterator it; + for (it=_standaloneData.begin(); it!=_standaloneData.end(); ++it) { + if ( !it.data().externals.contains(url) ) continue; + if ( !it.key().exists() ) continue; + type = it.data().type; + return it.key(); + } + type = PURL::Nb_FileTypes; + return url; +} + +void ProjectManager::View::insertSourceFiles() +{ + Q_ASSERT(_project); + PURL::UrlList list = PURL::getOpenUrls(":<sources>", PURL::sourceFilter(PURL::CompleteFilter), this, i18n("Select Source File")); + if ( list.isEmpty() ) return; + PURL::UrlList::const_iterator it; + for (it=list.begin(); it!=list.end(); ++it) insertFile(*it); +} + +void ProjectManager::View::insertObjectFiles() +{ + Q_ASSERT(_project); + PURL::UrlList list = PURL::getOpenUrls(":<objects>", PURL::objectFilter(PURL::CompleteFilter), this, i18n("Select Object File")); + if ( list.isEmpty() ) return; + PURL::UrlList::const_iterator it; + for (it=list.begin(); it!=list.end(); ++it) insertFile(*it); +} + +void ProjectManager::View::insertFile(const PURL::Url &url) +{ + if ( !url.exists() ) { + MessageBox::detailedSorry(i18n("Could not find file."), i18n("File: %1").arg(url.pretty()), Log::Show); + return; + } + PURL::Url purl = url; + MessageBox::Result copy = MessageBox::No; + if ( !url.isInto(_project->directory()) ) { + copy = MessageBox::questionYesNoCancel(i18n("File \"%1\" is not inside the project directory. Do you want to copy the file to your project directory?").arg(url.pretty()), + i18n("Copy and Add"), i18n("Add only")); + if ( copy==MessageBox::Cancel ) return; + if ( copy==MessageBox::Yes ) purl = PURL::Url(_project->directory(), url.filename()); + } + if ( _project->absoluteFiles().contains(purl) ) { + MessageBox::detailedSorry(i18n("File is already in the project."), i18n("File: %1").arg(purl.pretty()), Log::Show); + return; + } + if ( copy==MessageBox::Yes ) { + Log::StringView sview; + if ( !url.copyTo(purl, sview) ) { + MessageBox::detailedSorry(i18n("Copying file to project directory failed."), i18n("File: %1\n").arg(url.pretty()) + sview.string(), Log::Show); + return; + } + } + _project->addFile(purl); + addFile(purl, purl.fileType(), Intrinsic); +} + +bool ProjectManager::View::openProject() +{ + PURL::Url url = PURL::getOpenUrl(":open_project", PURL::projectFilter(PURL::CompleteFilter), this, i18n("Select Project file")); + return openProject(url); +} + +void ProjectManager::View::addExternalFile(const PURL::Url &url, FileOrigin origin) +{ + Q_ASSERT( origin!=Intrinsic ); + addFile(url, url.fileType(), origin); +} + +const ProjectManager::View::ProjectData &ProjectManager::View::projectData() const +{ + if ( _project==0 ) return _standaloneData[projectUrl()]; + return _projectData; +} + +ProjectManager::View::ProjectData &ProjectManager::View::projectData() +{ + if ( _project==0 ) return _standaloneData[projectUrl()]; + return _projectData; +} + +void ProjectManager::View::addFile(const PURL::Url &url, PURL::FileType type, FileOrigin origin) +{ + if ( contains(url) ) return; + QMap<PURL::Url, FileOrigin> &ext = projectData().externals; + if ( type.data().group==PURL::LinkerScript && _linkerScriptItem ) { + _linkerScriptItem->set(url); + ext[url] = Included; + return; + } + PURL::FileProperties properties = type.data().properties; + Group grp = Nb_Groups; + switch (origin) { + case Intrinsic: grp = group(type); break; + case Generated: grp = GeneratedGroup; break; + case Included: grp = IncludedGroup; break; + } + HeaderItem *hitem = headerItem(grp); + QListViewItem *item = new FileItem(hitem, type, url, origin!=Intrinsic); + item->moveItem(hitem->lastChild()); + ensureItemVisible(item); + if ( origin!=Intrinsic ) ext[url] = origin; + if ( type==PURL::Hex && _project==0 ) { + QString extension = PURL::extension(PURL::AsmGPAsm); + PURL::Url durl = PURL::Url::fromPathOrUrl("<" + (url.isEmpty() ? i18n("Disassembly") : url.appendExtension(extension).filename()) + ">"); + if ( findFileItem(durl)==0 ) { + (void)new FileItem(headerItem(ViewGroup), PURL::Coff, durl, true); + ext[durl] = Generated; + } + } + if ( _project && origin==Intrinsic ) _modified = true; +} + +void ProjectManager::View::removeExternalFiles() +{ + QMap<PURL::Url, FileOrigin> &ext = projectData().externals; + QMap<PURL::Url, FileOrigin>::const_iterator it; + for (it=ext.begin(); it!=ext.end(); ++it) { + Main::editorManager().closeEditor(it.key()); + removeFile(it.key()); + } + ext.clear(); + if (_linkerScriptItem) _linkerScriptItem->init(); +} + +void ProjectManager::View::removeFile(const PURL::Url &url) +{ + if ( _project && !isExternalFile(url) ) _project->removeFile(url); + FileItem *item = findFileItem(url); + if ( item==0 ) return; + HeaderItem *group = static_cast<HeaderItem *>(item->parent()); + delete item; + if ( group->childCount()==0 ) delete group; + _modified = true; + emit guiChanged(); +} + +void ProjectManager::View::clicked(int button, QListViewItem *item, const QPoint &, int) +{ + if ( item==0 ) return; + if ( button!=LeftButton ) return; + const Device::Data *data = Main::deviceData(); + Rtti rtti = Rtti(item->rtti()); + if ( data==0 && rtti!=DeviceRtti && rtti!=RootRtti ) { + MessageBox::sorry(i18n("Cannot open without device specified."), Log::Show); + return; + } + Editor *e = 0; + ::BusyCursor bc; + switch (rtti) { + case RootRtti: + Main::toplevel().configureProject(); + break; + case HeaderRtti: { + if ( static_cast<HeaderItem *>(item)->group()!=DeviceGroup ) break; + e = Main::editorManager().openEditor(EditorManager::DeviceEditor); + break; + } + case RegisterRtti: + e = Main::editorManager().openEditor(EditorManager::RegisterEditor); + break; + case DeviceRtti: return; + case LinkerScriptRtti: { + PURL::Url url = Main::projectManager().linkerScriptUrl(); + if ( url.isEmpty() ) break; + e = Main::editorManager().findEditor(url); + if ( e==0 ) { + e = Main::editorManager().createEditor(url.fileType(), url); + if ( !e->open(url) ) { + delete e; + break; + } + if ( e && isExternalFile(url) ) e->setReadOnly(true); + Main::editorManager().addEditor(e); + } else Main::editorManager().showEditor(e); + break; + } + case FileRtti: { + FileItem *fi = static_cast<FileItem *>(item); + if ( !(fi->ftype().data().properties & PURL::Editable) ) break; + e = Main::editorManager().findEditor(fi->url()); + if ( e==0 ) { + if ( fi->ftype()==PURL::Coff && _project==0 && !fi->url().exists() ) { + PURL::Url url = findFileItem(PURL::Hex)->url(); + if ( url.isEmpty() ) { + HexEditor *he = ::qt_cast<HexEditor *>(Main::currentEditor()); + if ( he==0 ) break; + e = new DisassemblyEditor(*he, *data, this); + } else e = new DisassemblyEditor(url, *data, this); + addExternalFile(fi->url(), Generated); + } else e = Main::editorManager().createEditor(fi->url().fileType(), fi->url()); + if ( e==0 ) break; + if ( !e->open(fi->url()) ) { + delete e; + break; + } + if ( isExternalFile(fi->url()) ) e->setReadOnly(true); + Main::editorManager().addEditor(e); + } else Main::editorManager().showEditor(e); + break; + } + } + cancelRenaming(); + emit guiChanged(); +} + +void ProjectManager::View::insertCurrentFile() +{ + insertFile(Main::editorManager().currentEditor()->url()); +} + +bool ProjectManager::View::editProject() +{ + ProjectEditor dialog(*_project, this); + if ( dialog.exec()!=QDialog::Accepted ) return false; + _modified = true; + if (_linkerScriptItem) _linkerScriptItem->init(); + return true; +} + +bool ProjectManager::View::newProject() +{ + ProjectWizard wizard(this); + if ( wizard.exec()==QDialog::Rejected ) return false; + closeProject(); + QString error; + if ( !wizard.project()->save(error) ) { + MessageBox::detailedSorry(i18n("Failed to create new project file"), error, Log::Show); + return false; + } + openProject(wizard.url()); + return true; +} + +void ProjectManager::View::setProject(Project *project) +{ + closeProject(); + Main::editorManager().closeAllEditors(); + _project = project; + _rootItem->set(project->url(), false); + if ( project && Main::toolGroup().linkerScriptType()!=PURL::Nb_FileTypes ) { + _linkerScriptItem = new LinkerScriptItem(headerItem(LinkerScriptGroup)); + ensureItemVisible(_linkerScriptItem); + } +} + +bool ProjectManager::View::openProject(const PURL::Url &url) +{ + if ( url.isEmpty() ) return false; + bool reload = ( _project && _project->url()==url ); + if ( reload && !MessageBox::askContinue(i18n("Project already loaded. Reload?"), i18n("Reload")) ) return false; + static_cast< KRecentFilesAction *>(Main::action("project_open_recent"))->removeURL(url.kurl()); + Project *p = new Project(url); + QString error; + if ( !p->load(error) ) { + MessageBox::detailedSorry(i18n("Could not open project file."), error, Log::Show); + delete p; + return false; + } + setProject(p); + PURL::UrlList files = _project->absoluteFiles(); + PURL::UrlList::const_iterator it; + for(it=files.begin(); it!=files.end(); ++it) addFile(*it, (*it).fileType(), Intrinsic); + _projectData.type = PURL::Project; + _projectData.externals.clear(); + static_cast<KRecentFilesAction *>(Main::action("project_open_recent"))->addURL(url.kurl()); + files = _project->openedFiles(); + for(it = files.begin(); it!=files.end(); ++it) Main::editorManager().openFile(*it); + Register::list().init(); + QValueList<Register::TypeData> watched = _project->watchedRegisters(); + QValueList<Register::TypeData>::const_iterator wit; + for (wit=watched.begin(); wit!=watched.end(); ++wit) Register::list().setWatched(*wit, true); + return true; +} + +bool ProjectManager::View::isExternalFile(const PURL::Url &url) const +{ + if ( projectUrl().isEmpty() ) return false; + return projectData().externals.contains(url); +} + +void ProjectManager::View::modified(const PURL::Url &url) +{ + FileItem *item = findFileItem(url); + if ( item && !isExternalFile(url) ) _modified = true; +} + +void ProjectManager::View::renamed(QListViewItem *item, int, const QString &text) +{ + Q_ASSERT ( item->rtti()==DeviceRtti ); + Main::toplevel().setDevice(text); +} + +void ProjectManager::View::updateGUI() +{ + _deviceItem->updateText(); +} + +QDragObject *ProjectManager::View::dragObject() +{ + if ( currentItem()==0 || currentItem()->rtti()!=FileRtti ) return 0; + const FileItem *item = static_cast<const FileItem *>(currentItem()); + const HeaderItem *hitem = static_cast<const HeaderItem *>(item->parent()); + if ( hitem->group()!=SourceGroup ) return 0; + QStrList uris; + uris.append(QUriDrag::localFileToUri(item->url().filepath())); + return new QUriDrag(uris, viewport()); +} + +bool ProjectManager::View::acceptDrag(QDropEvent* e) const +{ + if ( e->source()!=viewport() ) return false; + const QListViewItem *item = itemAt(e->pos()); + if ( item==0 || item->rtti()!=FileRtti ) return false; + const HeaderItem *hitem = static_cast<const HeaderItem *>(item->parent()); + return ( hitem->group()==SourceGroup ); +} + +void ProjectManager::View::filesReordered() +{ + if ( _project==0 ) return; + _project->clearFiles(); + QListViewItem *item = headerItem(SourceGroup)->firstChild(); + for (;item; item=item->nextSibling()) + _project->addFile(static_cast<FileItem *>(item)->url()); +} + +QString ProjectManager::View::tooltip(QListViewItem *item, int) const +{ + switch (Rtti(item->rtti())) { + case RootRtti: + case FileRtti: + case LinkerScriptRtti: return static_cast<const UrlItem *>(item)->url().filepath(); + case DeviceRtti: + case RegisterRtti: + case HeaderRtti: break; + } + return QString::null; +} + +PURL::Url ProjectManager::View::linkerScriptUrl() const +{ + QListViewItemIterator it(const_cast<View *>(this)); + for(; it.current(); ++it) { + if ( it.current()->rtti()!=LinkerScriptRtti ) continue; + return static_cast<LinkerScriptItem *>(it.current())->url(); + } + return PURL::Url(); +} + +bool ProjectManager::View::needsRecompile() const +{ + // ### this could be perfected... + PURL::Url output = projectUrl().toFileType(PURL::Hex); + QDateTime outputLastModified; + if ( !output.exists(&outputLastModified) ) return true; + PURL::UrlList files; + if ( Main::project() ) files = Main::project()->absoluteFiles(); + else files.append(projectUrl()); + PURL::UrlList::const_iterator it; + for (it=files.begin(); it!=files.end(); ++it) { + QDateTime lastModified; + if ( !(*it).exists(&lastModified) ) continue; + if ( lastModified>outputLastModified ) return true; + } + return false; +} + +PURL::Url ProjectManager::View::selectedUrl() const +{ + QListViewItem *item = currentItem(); + if ( item==0 ) return PURL::Url(); + Rtti rtti = Rtti(item->rtti()); + if ( rtti!=FileRtti ) return PURL::Url(); + return static_cast<FileItem *>(item)->url(); +} diff --git a/src/libgui/project_manager.h b/src/libgui/project_manager.h new file mode 100644 index 0000000..2939f33 --- /dev/null +++ b/src/libgui/project_manager.h @@ -0,0 +1,106 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef PROJECT_MANAGER_H +#define PROJECT_MANAGER_H + +#include "common/global/purl.h" +#include "common/gui/misc_gui.h" +#include "common/gui/list_view.h" +#include "project_manager_ui.h" +class Project; +class Editor; +namespace Coff { class SectionParser; } + +namespace ProjectManager +{ + +class View : public ListView +{ +Q_OBJECT +public: + View(QWidget *parent); + virtual ~View(); + + bool editProject(); + bool newProject(); + bool openProject(); + bool openProject(const PURL::Url &url); + void closeProject(); + Project *project() const { return _project; } + + void setStandalone(const PURL::Url &url, PURL::FileType type); + PURL::Url projectUrl() const { return _rootItem->url(); } + PURL::Url standaloneGenerator(const PURL::Url &url, PURL::FileType &type) const; + PURL::Url linkerScriptUrl() const; + PURL::Url selectedUrl() const; + void removeFile(const PURL::Url &url); + void select(const Editor *e); + void insertFile(const PURL::Url &url); + bool contains(const PURL::Url &url) const { return findFileItem(url); } + void addExternalFile(const PURL::Url &url, FileOrigin fileOrigin); + bool isExternalFile(const PURL::Url &url) const; + void removeExternalFiles(); + + bool isModified() const { return _modified; } + void setModified(bool modified) { _modified = modified; } + bool needsRecompile() const; + +public slots: + void insertSourceFiles(); + void insertObjectFiles(); + void insertCurrentFile(); + void updateGUI(); + +private slots: + void init(); + void contextMenu(QListViewItem *item, const QPoint &pos, int column); + void clicked(int button, QListViewItem *item, const QPoint &pos, int column); + void renamed(QListViewItem *item, int column, const QString &text); + void modified(const PURL::Url &url); + void filesReordered(); + +signals: + void guiChanged(); + +private: + Project *_project; + RootItem *_rootItem; + DeviceItem *_deviceItem; + LinkerScriptItem *_linkerScriptItem; + class ProjectData { + public: + PURL::FileType type; + QMap<PURL::Url, FileOrigin> externals; + }; + QMap<PURL::Url, ProjectData> _standaloneData; + ProjectData _projectData; + bool _modified; + + HeaderItem *findHeaderItem(Group group) const; + HeaderItem *headerItem(Group group); + FileItem *findFileItem(const PURL::Url &url) const; + FileItem *findFileItem(PURL::FileType type) const; + QListViewItem *findItem(const QString &name) const; + virtual QDragObject *dragObject(); + virtual bool acceptDrag(QDropEvent* e) const; + virtual QString tooltip(QListViewItem *item, int col) const; + void addExternalFiles(); + void rightClicked(QListViewItem *item, const QPoint &pos); + void leftClicked(QListViewItem *item); + void addFile(const PURL::Url &url, PURL::FileType type, FileOrigin origin); + void setProject(Project *project); + void initListView(); + ProjectData &projectData(); + const ProjectData &projectData() const; +}; + +} // namespace + +#endif diff --git a/src/libgui/project_manager_ui.cpp b/src/libgui/project_manager_ui.cpp new file mode 100644 index 0000000..235d360 --- /dev/null +++ b/src/libgui/project_manager_ui.cpp @@ -0,0 +1,185 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "project_manager_ui.h" + +#include <qpainter.h> +#include <kiconloader.h> + +#include "project.h" +#include "devices/list/device_list.h" +#include "main_global.h" +#include "common/gui/purl_gui.h" +#include "device_gui.h" + +//---------------------------------------------------------------------------- +void PopupMenu::insertItem(const QString &icon, const QString &label, QObject *receiver, const char *slot) +{ + KIconLoader loader; + QPixmap pixmap = loader.loadIcon(icon, KIcon::Small); + if (receiver) KPopupMenu::insertItem(pixmap, label, receiver, slot, 0, _index); + else KPopupMenu::insertItem(pixmap, label, _index); + _index++; +} + +//---------------------------------------------------------------------------- +const char *ProjectManager::HeaderItem::GROUP_LABELS[Nb_Groups] = { + I18N_NOOP("Device"), I18N_NOOP("Headers"), I18N_NOOP("Linker Script"), + I18N_NOOP("Sources"), I18N_NOOP("Objects"), I18N_NOOP("Views"), + I18N_NOOP("Generated"), I18N_NOOP("Included") +}; + +ProjectManager::Group ProjectManager::group(PURL::FileType type) +{ + switch (type.data().group) { + case PURL::Source: return SourceGroup; + case PURL::Header: return HeaderGroup; + case PURL::LinkerScript: return LinkerScriptGroup; + case PURL::LinkerObject: return LinkerObjectGroup; + case PURL::Nb_FileGroups: break; + } + return ViewGroup; +} + +ProjectManager::RootItem::RootItem(KListView *listview) + : UrlItem(listview) +{ + setSelectable(false); + setPixmap(0, PURL::icon(PURL::Project)); + set(PURL::Url(), true); +} + +void ProjectManager::RootItem::set(const PURL::Url &url, bool standalone) +{ + _url = url; + _standalone = standalone; + if ( _url.isEmpty() ) setText(0, i18n("<no project>")); + else if (_standalone) setText(0, i18n("Standalone File")); + else setText(0, _url.basename()); +} + +ProjectManager::HeaderItem::HeaderItem(RootItem *item, Group group) + : KListViewItem(item), _group(group) +{ + if ( group!=DeviceGroup) setSelectable(false); + setText(0, i18n(GROUP_LABELS[group])); +} + +QListViewItem *ProjectManager::HeaderItem::lastChild() const +{ + QListViewItem *item = firstChild(); + if ( item==0 ) return 0; + for (;;) { + if ( item->nextSibling()==0 ) break; + item = item->nextSibling(); + } + return item; +} + +ProjectManager::FileItem::FileItem(HeaderItem *item, PURL::FileType ftype, + const PURL::Url &url, bool external) + : UrlItem(item), _ftype(ftype), _external(external) +{ + setPixmap(0, PURL::icon(ftype)); + set(url); +} + +void ProjectManager::FileItem::set(const PURL::Url &url) +{ + _url = url; + switch (_ftype.type()) { + case PURL::Hex: setText(0, i18n("Hex File")); break; + case PURL::Coff: setText(0, i18n("Disassembly Listing")); break; + case PURL::Lst: setText(0, i18n("List")); break; + case PURL::Map: setText(0, i18n("Memory Map")); break; + case PURL::Project: + case PURL::Nb_FileTypes: Q_ASSERT(false); break; + default: { + QString s = url.filename(); + if ( _external && group(_ftype)==LinkerScriptGroup ) + s += i18n(" (default)"); + setText(0, s); break; + } + } +} + +void ProjectManager::FileItem::paintCell(QPainter *p, const QColorGroup &cg, + int column, int width, int align) +{ + QFont f = p->font(); + f.setItalic(group(_ftype)!=ViewGroup && _external); + p->setFont(f); + KListViewItem::paintCell(p, cg, column, width, align); +} + +ProjectManager::RegisterItem::RegisterItem(HeaderItem *item) + : KListViewItem(item) +{ + KIconLoader loader; + QPixmap chip = loader.loadIcon("piklab_chip", KIcon::Small); + setPixmap(0, chip); + setText(0, i18n("Registers")); +} + +ProjectManager::DeviceItem::DeviceItem(HeaderItem *item) + : EditListViewItem(item) +{} + +QWidget *ProjectManager::DeviceItem::editWidgetFactory(int) const +{ + QComboBox *combo = new DeviceChooser::ComboBox(Main::project()==0, 0); + QString device = Main::device(); + if ( device!=Device::AUTO_DATA.name ) combo->setCurrentText(device); + QObject::connect(combo, SIGNAL(activated(int)), listView(), SLOT(finishRenaming())); + return combo; +} + +void ProjectManager::DeviceItem::updateText() +{ + QString device = Main::device(); + if ( device==Device::AUTO_DATA.name ) { + const Device::Data *data = Main::deviceData(); + if (data) device = data->name() + " " + i18n(Device::AUTO_DATA.label); + else device = i18n(Device::AUTO_DATA.label); + } + setText(0, device); +} + +ProjectManager::LinkerScriptItem::LinkerScriptItem(HeaderItem *item) + : UrlItem(item) +{ + init(); +} + +void ProjectManager::LinkerScriptItem::init() +{ + _url = PURL::Url(); + PURL::Url lkr; + if ( Main::project() ) lkr = Main::project()->customLinkerScript(); + setText(0, lkr.isEmpty() ? i18n("<default>") : lkr.filename()); + setPixmap(0, lkr.isEmpty() ? QPixmap() : PURL::icon(PURL::Lkr)); +} + +void ProjectManager::LinkerScriptItem::set(const PURL::Url &url) +{ + _url = url; + QString s = url.filename(); + PURL::Url lkr; + if ( Main::project() ) lkr = Main::project()->customLinkerScript(); + if ( lkr.isEmpty() ) s += i18n(" (default)"); + setText(0, s); + setPixmap(0, PURL::icon(PURL::Lkr)); +} + +PURL::Url ProjectManager::LinkerScriptItem::url() const +{ + if ( !_url.isEmpty() ) return _url; + if ( Main::project() ) return Main::project()->customLinkerScript(); + return PURL::Url(); +} diff --git a/src/libgui/project_manager_ui.h b/src/libgui/project_manager_ui.h new file mode 100644 index 0000000..012eb64 --- /dev/null +++ b/src/libgui/project_manager_ui.h @@ -0,0 +1,121 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef PROJECT_MANAGER_UI_H +#define PROJECT_MANAGER_UI_H + +#include <kpopupmenu.h> + +#include "common/global/purl.h" +#include "common/gui/misc_gui.h" +#include "common/gui/list_view.h" + +//----------------------------------------------------------------------------- +class PopupMenu : public KPopupMenu +{ +Q_OBJECT +public: + PopupMenu() : _index(1) {} + void insertItem(const QString &icon, const QString &label, QObject *receiver = 0, const char *slot = 0); + +private: + uint _index; +}; + +//----------------------------------------------------------------------------- +namespace ProjectManager +{ + enum Rtti { RootRtti = 1000, HeaderRtti, FileRtti, DeviceRtti, RegisterRtti, LinkerScriptRtti }; + enum Group { DeviceGroup = 0, HeaderGroup, LinkerScriptGroup, SourceGroup, + LinkerObjectGroup, ViewGroup, GeneratedGroup, IncludedGroup, Nb_Groups }; + extern Group group(PURL::FileType type); + enum FileOrigin { Intrinsic, Generated, Included }; + +class UrlItem : public KListViewItem +{ +public: + UrlItem(KListView *listview) : KListViewItem(listview) {} + UrlItem(KListViewItem *item) : KListViewItem(item) {} + virtual PURL::Url url() const { return _url; } + +protected: + PURL::Url _url; +}; + +class RootItem : public UrlItem +{ +public: + RootItem(KListView *listview); + void set(const PURL::Url &url, bool standAlone); + virtual int rtti() const { return RootRtti; } + +private: + bool _standalone; +}; + +class HeaderItem : public KListViewItem +{ +public: + HeaderItem(RootItem *item, Group group); + virtual int rtti() const { return HeaderRtti; } + Group group() const { return _group; } + QListViewItem *lastChild() const; + +private: + static const char *GROUP_LABELS[Nb_Groups]; + Group _group; +}; + +class FileItem : public UrlItem +{ +public: + FileItem(HeaderItem *item, PURL::FileType type, const PURL::Url &url, bool external); + virtual int rtti() const { return FileRtti; } + PURL::FileType ftype() const { return _ftype; } + +private: + PURL::FileType _ftype; + bool _external; + + void set(const PURL::Url &url); + virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align); +}; + +class RegisterItem : public KListViewItem +{ +public: + RegisterItem(HeaderItem *item); + virtual int rtti() const { return RegisterRtti; } +}; + +class DeviceItem : public EditListViewItem +{ +public: + DeviceItem(HeaderItem *item); + void updateText(); + virtual int rtti() const { return DeviceRtti; } + +private: + virtual QWidget *editWidgetFactory(int) const; + virtual bool alwaysAcceptEdit(int) const { return true; } +}; + +class LinkerScriptItem : public UrlItem +{ +public: + LinkerScriptItem(HeaderItem *item); + void set(const PURL::Url &url); + virtual PURL::Url url() const; + void init(); + virtual int rtti() const { return LinkerScriptRtti; } +}; + +} // namespace + +#endif diff --git a/src/libgui/project_wizard.cpp b/src/libgui/project_wizard.cpp new file mode 100644 index 0000000..b4d26df --- /dev/null +++ b/src/libgui/project_wizard.cpp @@ -0,0 +1,283 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "project_wizard.h" + +#include <qheader.h> +#include <qvbuttongroup.h> +#include <qradiobutton.h> +#include <qstyle.h> +#include <kfiledialog.h> +#include <kiconloader.h> + +#include "common/gui/purl_gui.h" +#include "device_gui.h" +#include "tools/list/tool_list.h" +#include "tools/list/compile_config.h" +#include "main_global.h" +#include "project.h" +#include "tools/list/compile_process.h" +#include "common/gui/editlistbox.h" +#include "devices/list/device_list.h" + +//----------------------------------------------------------------------------- +FileListItem::FileListItem(KListView *view) + : KListViewItem(view), _group(0), _copy(true) +{ + KIconLoader loader; + _pixmap = loader.loadIcon("button_ok", KIcon::Small); +} + +void FileListItem::toggle() +{ + _copy = !_copy; + repaint(); +} + +PURL::FileGroup FileListItem::fileGroup() const +{ + if ( _group==0 ) return PURL::Nb_FileGroups; + PURL::Url url = PURL::Url::fromPathOrUrl(text(1)); + switch (url.data().group) { + case PURL::Source: { + FOR_EACH(PURL::ToolType, type) + if ( _group->implementationType(type)==url.fileType() ) return PURL::Source; + break; + } + case PURL::Header: return PURL::Header; + case PURL::LinkerScript: { + if ( _group->linkerScriptType()==url.fileType() ) return PURL::LinkerScript; + break; + } + case PURL::LinkerObject: return PURL::LinkerObject; + case PURL::Nb_FileGroups: break; + } + return PURL::Nb_FileGroups; +} + +const QPixmap *FileListItem::pixmap(int column) const +{ + + if ( column==0 && _copy ) return &_pixmap; + return KListViewItem::pixmap(column); +} + +//----------------------------------------------------------------------------- +FileListBox::FileListBox(QWidget *parent) + : EditListBox(2, 0, 0, parent, "file_list_box") +{ + _listView->header()->show(); + _listView->header()->setClickEnabled(false); + _listView->header()->setResizeEnabled(false); + _listView->header()->setMovingEnabled(false); + _listView->setColumnText(0, i18n("Copy")); + int spacing = style().pixelMetric(QStyle::PM_HeaderMargin); + QFontMetrics fm(font()); + _listView->header()->resizeSection(0, fm.width(i18n("Copy")) + 2*spacing); // hack + _listView->setColumnText(1, i18n("Filename")); + _listView->setAllColumnsShowFocus(true); + connect(_listView, SIGNAL(clicked(QListViewItem *, const QPoint &, int)), SLOT(clicked(QListViewItem *, const QPoint &, int))); +} + +void FileListBox::addItem() +{ + PURL::UrlList urls = PURL::getOpenUrls(_directory.path(), QString::null, this, i18n("Select Files")); + PURL::UrlList::const_iterator it; + for (it=urls.begin(); it!=urls.end(); ++it) EditListBox::addItem((*it).pretty()); +} + +QListViewItem *FileListBox::createItem() +{ + return new FileListItem(_listView); +} + +void FileListBox::clicked(QListViewItem *item, const QPoint &, int column) +{ + if ( item==0 || column!=0 ) return; + static_cast<FileListItem *>(item)->toggle(); +} + +void FileListBox::setToolGroup(const Tool::Group &group) +{ + QListViewItem *item = _listView->firstChild(); + for (; item; item = item->nextSibling()) static_cast<FileListItem *>(item)->setToolGroup(group); +} + +//----------------------------------------------------------------------------- +ProjectWizard::ProjectWizard(QWidget *parent) + : KWizard(parent, "project_wizard"), _project(0) +{ + // first page + _first = new QWidget(this); + addPage(_first, i18n("New Project: Basic Settings")); + setHelpEnabled(_first, false); + QGridLayout *grid = new QGridLayout(_first, 1, 1, 10, 10); + QLabel *label = new QLabel(i18n("Name:"), _first); + grid->addWidget(label, 0, 0); + _name = new KLineEdit(_first); + _name->setFocus(); + grid->addMultiCellWidget(_name, 0,0, 1,2); + label = new QLabel(i18n("Directory:"), _first); + grid->addWidget(label, 1, 0); + _directory = new PURL::DirectoryWidget(":new_project", _first); + grid->addMultiCellWidget(_directory, 1,1, 1,2); + label = new QLabel(i18n("Device:"), _first); + grid->addWidget(label, 2, 0); + _device = new DeviceChooser::Button(false, _first); + _device->setDevice(Main::device()); + grid->addWidget(_device, 2, 1); + label = new QLabel(i18n("Toolchain:"), _first); + grid->addWidget(label, 3, 0); + _toolchain = new KeyComboBox<QString>(_first); + Tool::Lister::ConstIterator it; + for (it=Tool::lister().begin(); it!=Tool::lister().end(); ++it) + _toolchain->appendItem(it.key(), it.data()->label()); + _toolchain->setCurrentItem(Main::toolGroup().name()); + grid->addWidget(_toolchain->widget(), 3, 1); + grid->setColStretch(2, 1); + grid->setRowStretch(4, 1); + + // second page + _second = new QWidget(this); + addPage(_second, i18n("New Project: Source Files")); + grid = new QGridLayout(_second, 1, 1, 10, 10); + _bgroup = new QVButtonGroup(i18n("Add Source Files"), _second); + _templateButton = new QRadioButton(i18n("Create template source file."), _bgroup); + _addButton = new QRadioButton(i18n("Add existing files."), _bgroup); + (void)new QRadioButton(i18n("Do not add files now."), _bgroup); + connect(_bgroup, SIGNAL(clicked(int)), SLOT(buttonClicked(int))); + grid->addWidget(_bgroup, 0, 0); + + // third page + _third = new QWidget(this); + addPage(_third, i18n("New Project: Add Files")); + setHelpEnabled(_third, false); + setFinishEnabled(_third, true); + grid = new QGridLayout(_third, 1, 1, 10, 10); + _files = new FileListBox(_third); + grid->addWidget(_files, 0, 0); +} + +void ProjectWizard::next() +{ + if ( currentPage()==_first ) { + QString name = _name->text().stripWhiteSpace(); + if ( name.isEmpty() ) { + MessageBox::sorry(i18n("Project name is empty."), Log::Show); + return; + } + PURL::Directory directory = _directory->directory(); + if ( directory.isEmpty() ) { + MessageBox::sorry(i18n("Directory is empty."), Log::Show); + return; + } + Log::StringView sview; + if ( !directory.exists() ) { + if ( !MessageBox::askContinue(i18n("Directory does not exists. Create it?")) ) return; + if ( !_directory->directory().create(sview) ) { + MessageBox::detailedSorry(i18n("Error creating directory."), sview.string(), Log::Show); + return; + } + } else if ( url().exists() ) { + if ( !MessageBox::askContinue(i18n("Project \"%1\"already exists. Overwrite it?").arg(url().filename())) ) return; + } + if ( !toolchain().check(device(), &Main::compileLog()) ) return; + _files->setDirectory(_directory->directory()); + _files->setToolGroup(toolchain()); + if ( toolchain().name()=="custom" ) { + _templateButton->hide(); + _addButton->setChecked(true); + } else { + _templateButton->show(); + _templateButton->setChecked(true); + } + buttonClicked(0); + } + if ( currentPage()==_third ) { + uint nb = 0; + for (uint i=0; i<_files->count(); i++) + if ( static_cast<const FileListItem *>(_files->item(i))->fileGroup()==PURL::Source ) nb++; + if ( toolchain().compileType()==Tool::SingleFile && nb>1 ) { + if ( !MessageBox::askContinue(i18n("The selected toolchain can only compile a single source file and you have selected %1 source files. Continue anyway? ").arg(nb)) ) return; + } + } + KWizard::next(); +} + +void ProjectWizard::done(int r) +{ + if ( r==Accepted ) { + PURL::UrlList files; + _project = new Project(url()); + Compile::Config::setDevice(_project, device()); + Compile::Config::setToolGroup(_project, toolchain()); + Compile::Config::setCustomCommands(_project, Compile::Config::customCommands(0)); + + if ( _bgroup->selectedId()==0 ) { + PURL::ToolType ttype = PURL::ToolType::Compiler; + PURL::FileType ftype = PURL::Nb_FileTypes; + FOR_EACH(PURL::ToolType, i) { + PURL::FileType type = toolchain().implementationType(i); + if ( type==PURL::Nb_FileTypes ) continue; + ftype = type; + ttype = i; + } + Q_ASSERT( ftype!=PURL::Nb_FileTypes ); + PURL::Url turl = url().toFileType(ftype); + QString text; + const Tool::SourceGenerator *generator = toolchain().sourceGenerator(); + if ( generator==0 ) text = i18n("Template source file generation not implemented yet for this toolchain..."); + else { + bool ok = true; + const Device::Data *data = Device::lister().data(device()); + SourceLine::List lines; + SourceLine::List list = generator->templateSourceFile(ttype, *data, ok); + if ( !ok ) lines.appendTitle(i18n("Template source file generation only partially implemented.")); + lines += list; + text = SourceLine::text(ftype.data().sourceFamily, lines, 4); + } + Log::StringView sview; + if ( turl.write(text, sview) ) files += turl; + else MessageBox::detailedSorry(i18n("Error creating template file."), i18n("File: %1\n").arg(turl.pretty()) + sview.string(), Log::Show); + _project->setOpenedFiles(files); + } else { + Log::StringView sview; + for (uint i=0; i<_files->count(); i++) { + PURL::Url furl = PURL::Url::fromPathOrUrl(_files->text(i)); + if ( static_cast<const FileListItem *>(_files->item(i))->copy() ) { + PURL::Url to(url().directory(), furl.filename()); + if ( furl==to || furl.copyTo(to, sview) ) files += to; + } else files += furl; + } + } + PURL::UrlList::const_iterator it; + for (it=files.begin(); it!=files.end(); ++it) _project->addFile(*it); + } + KWizard::done(r); +} + +PURL::Url ProjectWizard::url() const +{ + return PURL::Url(PURL::Directory(_directory->directory()), _name->text(), PURL::Project); +} + +const Tool::Group &ProjectWizard::toolchain() const +{ + return *Tool::lister().group(_toolchain->currentItem()); +} + +QString ProjectWizard::device() const +{ + return _device->device(); +} + +void ProjectWizard::buttonClicked(int id) +{ + setNextEnabled(_second, id==1); + setFinishEnabled(_second, id!=1); +} diff --git a/src/libgui/project_wizard.h b/src/libgui/project_wizard.h new file mode 100644 index 0000000..312ef01 --- /dev/null +++ b/src/libgui/project_wizard.h @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef PROJECT_WIZARD_H +#define PROJECT_WIZARD_H + +#include <qbuttongroup.h> +#include <qradiobutton.h> +#include <kwizard.h> +#include <klineedit.h> +#include <kcombobox.h> + +#include "common/global/purl.h" +#include "common/gui/editlistbox.h" +#include "common/gui/key_gui.h" +namespace PURL { class DirectoryWidget; } +namespace DeviceChooser { class Button; } +namespace Tool { class Group; } +class Project; + +//----------------------------------------------------------------------------- +class FileListItem : public KListViewItem +{ +public: + FileListItem(KListView *view); + void setToolGroup(const Tool::Group &group) { _group = &group; } + bool copy() const { return _copy; } + void toggle(); + PURL::FileGroup fileGroup() const; + virtual const QPixmap *pixmap(int column) const; + +private: + const Tool::Group *_group; + QPixmap _pixmap; + bool _copy; +}; + +class FileListBox : public EditListBox +{ +Q_OBJECT +public: + FileListBox(QWidget *parent); + void setDirectory(const PURL::Directory &directory) { _directory = directory; } + void setToolGroup(const Tool::Group &group); + +protected slots: + virtual void addItem(); + virtual void clicked(QListViewItem *item, const QPoint &point, int column); + +private: + PURL::Directory _directory; + + virtual uint textColumn() const { return 1; } + virtual QListViewItem *createItem(); +}; + +//----------------------------------------------------------------------------- +class ProjectWizard : public KWizard +{ +Q_OBJECT +public: + ProjectWizard(QWidget *parent); + PURL::Url url() const; + Project *project() const { return _project; } + +protected slots: + void buttonClicked(int id); + virtual void next(); + virtual void done(int r); + +private: + QWidget *_first, *_second, *_third; + KLineEdit *_name; + PURL::DirectoryWidget *_directory; + DeviceChooser::Button *_device; + KeyComboBox<QString> *_toolchain; + QButtonGroup *_bgroup; + QRadioButton *_templateButton, *_addButton; + FileListBox *_files; + Project *_project; + + QString device() const; + const Tool::Group &toolchain() const; +}; + +#endif diff --git a/src/libgui/register_view.cpp b/src/libgui/register_view.cpp new file mode 100644 index 0000000..3c244e8 --- /dev/null +++ b/src/libgui/register_view.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "register_view.h" + +#include <qlayout.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qcheckbox.h> +#include <klocale.h> + +#include "devices/base/device_group.h" +#include "devices/gui/device_group_ui.h" +#include "progs/base/prog_group.h" +#include "common/gui/misc_gui.h" +#include "main_global.h" +#include "editor_manager.h" +#include "gui_debug_manager.h" + +//----------------------------------------------------------------------------- +Register::MainView::MainView(const QString &title, const QString &tag, QWidget *parent) + : DeviceEditor(title, tag, parent, "register_view"), _debugging(false) +{} + +void Register::MainView::setDevice(bool force) +{ + bool oldDebugging = _debugging; + _debugging = Main::programmerGroup().isDebugger(); + DeviceEditor::setDevice(force || oldDebugging!=_debugging); +} + +QWidget *Register::MainView::createView(const Device::Data *data, QWidget *parent) +{ + if ( data==0 ) return new QWidget(parent); + Register::View *view = Device::groupui(*data).createRegisterView(parent); + if (view) view->updateView(); + else { + QWidget *w = new QWidget(parent); + QVBoxLayout *vbox = new QVBoxLayout(w, 10, 10); + QLabel *label = new QLabel(i18n("The selected device has no register."), w); + vbox->addWidget(label); + vbox->addStretch(1); + return w; + } + return view; +} diff --git a/src/libgui/register_view.h b/src/libgui/register_view.h new file mode 100644 index 0000000..7d12f0d --- /dev/null +++ b/src/libgui/register_view.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef REGISTER_EDITOR_H +#define REGISTER_EDITOR_H + +#include "device_editor.h" +#include "devices/gui/register_view.h" + +namespace Register +{ +class View; + +//----------------------------------------------------------------------------- +class MainView : public DeviceEditor +{ +Q_OBJECT +public: + MainView(const QString &title, const QString &tag, QWidget *parent = 0); + virtual bool isModified() const { return false; } + virtual bool isReadOnly() const { return true; } + virtual void addGui() {} + virtual void removeGui() {} + virtual void setFocus() {} + virtual void setDevice(bool force = false); + Register::View *view() { return static_cast<Register::View *>(_view); } + +private: + bool _debugging; + virtual QWidget *createView(const Device::Data *, QWidget *parent); + virtual void setModifiedInternal(bool) {} + virtual void setReadOnlyInternal(bool) {} +}; + +} // namespace + +#endif diff --git a/src/libgui/text_editor.cpp b/src/libgui/text_editor.cpp new file mode 100644 index 0000000..aecbc99 --- /dev/null +++ b/src/libgui/text_editor.cpp @@ -0,0 +1,346 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "text_editor.h" + +#include <qfile.h> +#include <qtextedit.h> +#include <qlayout.h> + +#include <klibloader.h> +#include <kpopupmenu.h> +#include <kiconloader.h> +#include <kfiledialog.h> +#include <klocale.h> +#include <kapplication.h> +#include <ktexteditor/markinterface.h> + +#include "main_global.h" +#include "gui_debug_manager.h" +#include "editor_manager.h" +#include "global_config.h" +#include "toplevel.h" + +//----------------------------------------------------------------------------- +const TextEditor::MarkTypeData TextEditor::MARK_TYPE_DATA[Breakpoint::Nb_MarkTypes] = { + { KTextEditor::MarkInterface::Execution, "piklab_program_counter" }, + { KTextEditor::MarkInterface::markType08, "piklab_program_counter_disabled" }, + { KTextEditor::MarkInterface::BreakpointActive, "piklab_breakpoint_active" }, + { KTextEditor::MarkInterface::BreakpointDisabled, "piklab_breakpoint_disabled" }, + { KTextEditor::MarkInterface::BreakpointReached, "piklab_breakpoint_reached" }, + { KTextEditor::MarkInterface::Error, "piklab_breakpoint_invalid" } +}; + +QPixmap TextEditor::pixmap(Breakpoint::MarkType type) +{ + return SmallIcon(MARK_TYPE_DATA[type].pixmap); +} + +TextEditor::TextEditor(bool withDebugger, QWidget *parent, const char *name) + : Editor(parent, name), _view(0) +{ + KLibFactory *factory = KLibLoader::self()->factory("libkatepart"); + if ( factory==0 ) qFatal("Could not find katepart"); + _document = static_cast<Kate::Document *>(factory->create(this, "kate", "KTextEditor::Document")); + _oldModified = _document->isModified(); + _oldReadOnly = !_document->isReadWrite(); + + QVBoxLayout *top = new QVBoxLayout(this, 0, 10); + _split = new QSplitter(this); + _split->setFrameStyle(QFrame::TabWidgetPanel | QFrame::Sunken); + top->addWidget(_split); + + connect(_document, SIGNAL(hlChanged()), SLOT(highlightChanged())); + setAcceptDrops(true); + addView(); + + for (uint i=0; i<Breakpoint::Nb_MarkTypes; i++) + _document->setPixmap(KTextEditor::MarkInterface::MarkTypes(MARK_TYPE_DATA[i].type), pixmap(Breakpoint::MarkType(i))); + + if (withDebugger) QTimer::singleShot(0, this, SLOT(addToDebugManager())); +} + +bool TextEditor::open(const PURL::Url &url) +{ + setReadOnly(url.fileType().data().properties & PURL::ReadOnly); + if ( !_document->openURL(url.kurl()) ) return false; + _view->setEol(url.isDosFile() ? Dos : Unix); + highlightChanged(); + return true; +} + +void TextEditor::addToDebugManager() +{ + static_cast<Debugger::GuiManager *>(Debugger::manager)->addTextEditor(*this); +} + +bool TextEditor::eventFilter(QObject *, QEvent *e) +{ + if ( e->type()==QEvent::KeyPress ) { + if ( static_cast<QKeyEvent *>(e)->key()==Key_Escape ) return true; + } + return false; +} + +void TextEditor::addView() +{ + KTextEditor::View *v = _document->createView(_split); + if ( _view==0 ) _view = static_cast<Kate::View *>(v); + Q_ASSERT(v); + connect(v, SIGNAL(gotFocus(Kate::View *)), SLOT(gotFocus(Kate::View *))); + connect(v, SIGNAL(cursorPositionChanged()), SLOT(statusChanged())); + connect(v, SIGNAL(dropEventPass(QDropEvent *)), SIGNAL(dropEventPass(QDropEvent *))); + connect(v, SIGNAL(newStatus()), SLOT(statusChanged())); + v->show(); + v->setFocus(); + v->child(0, "KateViewInternal")->installEventFilter(this); + KTextEditor::PopupMenuInterface *pmi = KTextEditor::popupMenuInterface(v); + pmi->installPopup(&Main::popup("ktexteditor_popup")); + + // dispatch available space between views + QValueList<int> list = _split->sizes(); + QValueList<int>::Iterator it; + int sum = 0; + for (it = list.begin(); it!= list.end(); ++it) sum += *it; + sum /= list.size(); + for (it = list.begin(); it!=list.end(); ++it) *it = sum; + _split->setSizes(list); + + emit guiChanged(); +} + +void TextEditor::gotFocus(Kate::View *v) +{ + _view = v; + setFocusProxy(v); + statusChanged(); + emit guiChanged(); +} + +void TextEditor::addGui() +{ + Main::toplevel().guiFactory()->addClient(_view); +} + +void TextEditor::removeGui() +{ + Main::toplevel().guiFactory()->removeClient(_view); +} + +void TextEditor::removeCurrentView() +{ + delete _view; + _view = static_cast<Kate::View *>(_document->views().last()); + _document->views().last()->setFocus(); + emit guiChanged(); +} + +bool TextEditor::isReadOnly() const +{ + return !_document->isReadWrite(); +} + +void TextEditor::setReadOnlyInternal(bool ro) +{ + _oldReadOnly = ro; + _document->setReadWrite(!ro); +} + +bool TextEditor::isModified() const +{ + return _document->isModified(); +} + +void TextEditor::setModifiedInternal(bool m) +{ + _oldModified = m; + _document->setModified(m); +} + +void TextEditor::statusChanged() +{ + uint line, col; + _view->cursorPosition(&line, &col) ; + QString text = i18n("Line: %1 Col: %2").arg(line+1).arg(col+1); + if( isReadOnly() ) text += " " + i18n("R/O"); + emit statusTextChanged(" " + text + " "); + if ( isReadOnly()!=_oldReadOnly || isModified()!=_oldModified ) emit guiChanged(); + if ( isModified()!=_oldModified ) emit modified(); + _oldModified = isModified(); + _oldReadOnly = isReadOnly(); + Breakpoint::Data data(url(), line); + Breakpoint::updateActions(&data); +} + +uint TextEditor::highlightMode(const QString &name) const +{ + uint mode = 0; + for (; mode<_document->hlModeCount(); mode++) + if ( _document->hlModeName(mode)==name ) break; + return mode; +} + +void TextEditor::highlightChanged() +{ + if ( fileType()==PURL::Nb_FileTypes ) return; + // managed by hand because of collisions with file extensions + // used by other languages/softwares like other ASM and also PHP... + const char *name = fileType().data().highlightModeName; + if ( name==0 ) return; + uint mode = highlightMode(name); + if ( mode>=_document->hlModeCount() || _document->hlMode()==mode ) return; + _document->setHlMode(mode); +} + +uint TextEditor::cursorLine() const +{ + uint line; + _view->cursorPosition(&line, 0); + return line; +} + +void TextEditor::setMark(uint line, Breakpoint::MarkType type) +{ + _view->setIconBorder(true); + _document->setMark(line, MARK_TYPE_DATA[type].type); +} + +void TextEditor::clearMarks(uint type) +{ + QPtrList<KTextEditor::Mark> marks = _document->marks(); + QPtrListIterator<KTextEditor::Mark> it(marks); + for (; it.current(); ++it) + if ( it.current()->type==type ) _document->removeMark(it.current()->line, it.current()->type); +} + +void TextEditor::clearBreakpointMarks() +{ + for (uint i=0; i<Breakpoint::Nb_MarkTypes; i++) clearMarks(MARK_TYPE_DATA[i].type); +} + +QValueList<uint> TextEditor::bookmarkLines() const +{ + QValueList<uint> lines; + QPtrList<KTextEditor::Mark> marks = _document->marks(); + QPtrListIterator<KTextEditor::Mark> it(marks); + for (; it.current(); ++it) + if ( it.current()->type==KTextEditor::MarkInterface::Bookmark ) lines.append(it.current()->line); + return lines; +} + +void TextEditor::setBookmarkLines(const QValueList<uint> &lines) +{ + clearMarks(KTextEditor::MarkInterface::Bookmark); + QValueList<uint>::const_iterator it; + for (it=lines.begin(); it!=lines.end(); ++it) + _document->setMark(*it, KTextEditor::MarkInterface::Bookmark); +} + + +#if 0 +void TextEditor::slotChangedText() +{ + //This slot runs the instrucion set help bar, + // finds the current command word and compares it to the set of instrucions + //Found in the descript Qstringlist. + + + QString currentword; + QString testval; + + Kate::View *v = currentView(); + currentword = v->currentTextLine(); + //prepare the string for compareing + currentword = currentword.simplifyWhiteSpace(); + currentword = currentword.upper(); + + for ( QStringList::Iterator it = descript.begin(); it != descript.end(); ++it ) + { + testval = *it; + if(testval.startsWith(currentword.left(5))) + { + //if (testval.left(5) == currentword.left(5) ) { + lab_curword->setText(*it); + } + // else { + // lab_curword->setText("Pic Instruction Help"); + // } + } + + +} +#endif +#if 0 +void TextEditor::populateList() +{ + //Populate the qstringlist with the pic instruction set, and the text to go along with them + + descript += "CLRF : Clear F OPERANDS: f"; + descript += "ADDWF : Add W to F OPERANDS: f,d"; + descript += "ANDWF : AND W with F OPERANDS: f,d"; + descript += "CLRW : Clear W OPERANDS: NONE"; + descript += "COMF : Complement F OPERANDS: f,d"; + descript += "DECF : Decrement F OPERANDS: f,d"; + descript += "DECSSZ: Decrement F, Skip 0 OPERANDS: f,d"; + descript += "INCF : Increment F OPERANDS: f,d"; + descript += "INCFSZ: Increment F, Skip 0 OPERANDS: f,d"; + descript += "IORWF : Inclusive OR W with F OPERANDS: f,d"; + descript += "MOVF : Move F, OPERANDS: f,d"; + descript += "MOVWF : Move W to F OPERANDS: f,d"; + descript += "NOP : No Operation OPERANDS: NONE"; + descript += "RLF : Rotate Left F through Carry OPERANDS: f,d"; + descript += "RRF : Rotate Right F through Carry OPERANDS: f,d"; + descript += "SUBWF : Subtract W from F OPERANDS: f,d"; + descript += "SWAPF : Swap Nibbles in F OPERANDS: f,d"; + descript += "XORWF : Exclusive OR W with F OPERANDS: f,s"; + descript += "BCF : Bit Clear F OPERANDS: f,b"; + descript += "BSF : Bit Set F OPERANDS: f,b"; + descript += "BTFSC : Bit Test F, Skip if Clear OPERANDS: f,b"; + descript += "BTFSS : Bit Test F, Skip if Set OPERANDS: f,b"; + descript += "ADDLW : Add Literal and W OPERANDS: k"; + descript += "ANDLW : And Literal and W OPERANDS: k"; + descript += "CLRWDT: Clear Watchdog Timer OPERANDS: NONE"; + descript += "CALL : Call Subroutine OPERANDS: k"; + descript += "GOTO : Goto address OPERANDS: k"; + descript += "IORLW : Inclusive OR literal with W OPERANDS: k"; + descript += "MOVLW : Move Literal with W OPERANDS: k"; + descript += "RETFIE: Return From Interrupt OPERANDS: NONE"; + descript += "RETLW : Return with Literal in W OPERANDS: k"; + descript += "RETURN: Return from subroutine OPERANDS: NONE"; + descript += "SLEEP : Go into Standby Mode OPERANDS: NONE"; + descript += "SUBLW : Subtract W from Literal OPERANDS: k"; + descript += "XORLW : Exclusive OR Literal with W OPERANDS: k"; + +} +#endif + +//----------------------------------------------------------------------------- +SimpleTextEditor::SimpleTextEditor(bool withDebugger, PURL::FileType type, QWidget *parent, const char *name) + : TextEditor(withDebugger, parent, name), _type(type), _file(_sview) +{} + +SimpleTextEditor::SimpleTextEditor(bool withDebugger, QWidget *parent, const char *name) + : TextEditor(withDebugger, parent, name), _type(PURL::Nb_FileTypes), _file(_sview) +{} + +bool SimpleTextEditor::open(const PURL::Url &url) +{ + _type = url.fileType(); + return TextEditor::open(url); +} + +bool SimpleTextEditor::setText(const QString &text) +{ + _file.openForWrite(); + _file.appendText(text); + _file.close(); + if ( !_document->openURL(_file.url().kurl()) ) return false; + highlightChanged(); + return true; +} diff --git a/src/libgui/text_editor.h b/src/libgui/text_editor.h new file mode 100644 index 0000000..9c5a994 --- /dev/null +++ b/src/libgui/text_editor.h @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (C) 2005 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef TEXT_EDITOR_H +#define TEXT_EDITOR_H + +#include <qsplitter.h> +#include <qstringlist.h> +class QSplitter; + +#include <kate/view.h> +#include <kate/document.h> + +#include "common/gui/pfile_ext.h" +#include "editor.h" +#include "progs/manager/breakpoint.h" + +//----------------------------------------------------------------------------- +class TextEditor : public Editor +{ +Q_OBJECT +public: + TextEditor(bool withDebugger, QWidget *parent, const char *name = 0); + virtual PURL::FileType fileType() const { return url().fileType(); } + virtual PURL::Url url() const { return _document->url(); } + virtual bool isModified() const; + virtual bool isReadOnly() const; + virtual void addGui(); + virtual void removeGui(); + virtual void setFocus() { _view->setFocus(); } + static QPixmap pixmap(Breakpoint::MarkType type); + void setMark(uint line, Breakpoint::MarkType type); + void clearBreakpointMarks(); + void setCursor(uint line, uint column) { _view->setCursorPosition(line, column); } + uint cursorLine() const; + virtual bool open(const PURL::Url &url); + virtual bool save(const PURL::Url &url) { return _document->saveAs(url.kurl()); } + virtual bool eventFilter(QObject *o, QEvent *e); + virtual QValueList<uint> bookmarkLines() const; + virtual void setBookmarkLines(const QValueList<uint> &lines); + +public slots: + void addView(); + void removeCurrentView(); + void gotFocus(Kate::View *); + void highlightChanged(); + virtual void statusChanged(); + void selectAll() { _document->selectAll(); } + void deselect() { _document->clearSelection(); } + void copy() { _view->copy(); } + +protected: + enum EolType { Dos = 1, Unix = 0, Mac = 2 }; + Kate::Document *_document; + Kate::View *_view; + +private slots: + void addToDebugManager(); + +private: + QSplitter *_split; + bool _oldModified, _oldReadOnly; + struct MarkTypeData { + uint type; + const char *pixmap; + }; + static const MarkTypeData MARK_TYPE_DATA[Breakpoint::Nb_MarkTypes]; + +private: + virtual void setModifiedInternal(bool modified); + virtual void setReadOnlyInternal(bool readOnly); + uint highlightMode(const QString &name) const; + void clearMarks(uint type); +}; + +//----------------------------------------------------------------------------- +class SimpleTextEditor : public TextEditor +{ +Q_OBJECT +public: + SimpleTextEditor(bool withDebugger, PURL::FileType type, QWidget *parent, const char *name = 0); + SimpleTextEditor(bool withDebugger, QWidget *parent, const char *name = 0); + void setFileType(PURL::FileType type) { _type = type; } + virtual PURL::FileType fileType() const { return _type; } + bool setText(const QString &text); + virtual bool open(const PURL::Url &url); + +protected: + virtual bool load() { return false; } + +private: + Log::StringView _sview; + PURL::FileType _type; + PURL::TempFile _file; +}; + +#endif diff --git a/src/libgui/toplevel.cpp b/src/libgui/toplevel.cpp new file mode 100644 index 0000000..c757ace --- /dev/null +++ b/src/libgui/toplevel.cpp @@ -0,0 +1,993 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "toplevel.h" + +#include <qpixmap.h> +#include <qiconset.h> +#include <qlayout.h> +#include <qsplitter.h> +#include <qstringlist.h> +#include <qtimer.h> +#include <qprogressbar.h> +#include <qeventloop.h> +#include <qapplication.h> +#include <qtooltip.h> + +#include <kstatusbar.h> +#include <klocale.h> +#include <kedittoolbar.h> +#include <kapplication.h> +#include <kconfig.h> +#include <kaction.h> +#include <kcmdlineargs.h> +#include <kio/observer.h> +#include <kiconloader.h> +#include <kpopupmenu.h> +#include <khelpmenu.h> +#include <kmenubar.h> + +#include "gui_debug_manager.h" +#include "hex_editor.h" +#include "project_manager.h" +#include "project.h" +#include "global_config.h" +#include "editor.h" +#include "device_gui.h" +#include "text_editor.h" +#include "new_dialogs.h" +#include "common/global/process.h" +#include "common/gui/misc_gui.h" +#include "common/gui/purl_gui.h" +#include "devices/list/device_list.h" +#include "progs/base/prog_config.h" +#include "progs/list/prog_list.h" +#include "progs/gui/prog_group_ui.h" +#include "editor_manager.h" +#include "tools/list/compile_manager.h" +#include "object_view.h" +#include "config_gen.h" +#include "tools/list/compile_config.h" +#include "watch_view.h" +#include "coff/base/text_coff.h" +#include "tools/list/tool_list.h" +#include "breakpoint_view.h" +#include "main_global.h" +#include "gui_prog_manager.h" +#include "devices/gui/register_view.h" +#include "likeback.h" +#include "console.h" +#include "devices/base/device_group.h" +#include "tools/gui/toolchain_config_center.h" +#include "global_config.h" + +//---------------------------------------------------------------------------- +KDockWidget *MainWindow::createDock(const QString &name, const QPixmap &icon, + const QString &title, const DockPosition &position) +{ + KDockWidget *dock = createDockWidget(name, icon, 0, title); + dock->setDockSite(KDockWidget::DockCenter); + DockData ddata; + ddata.title = title; + ddata.position = position; + ddata.dock = dock; + ddata.action = new ViewMenuAction(dock); + connect(ddata.action, SIGNAL(activated(QWidget *)), SLOT(toggleToolView(QWidget *))); + _docks += ddata; + initDockPosition(ddata); + return dock; +} + +MainWindow::MainWindow() + : _configGenerator(0), _pikloopsProcess(0), _kfindProcess(0), _forceProgramAfterBuild(false) +{ + Q_ASSERT( Main::_toplevel==0 ); + Main::_toplevel = this; + +// status bar + _actionStatus = new QLabel(statusBar()); + statusBar()->addWidget(_actionStatus); + _actionProgress = new QProgressBar(statusBar()); + statusBar()->addWidget(_actionProgress); + _debugStatus = new QLabel(statusBar()); + statusBar()->addWidget(_debugStatus, 0, true); + _editorStatus = new QLabel(statusBar()); + statusBar()->addWidget(_editorStatus, 0, true); + _programmerStatus = new ProgrammerStatusWidget(statusBar()); + connect(_programmerStatus, SIGNAL(configure()), SLOT(configureProgrammer())); + connect(_programmerStatus, SIGNAL(selected(const Programmer::Group &)), SLOT(selectProgrammer(const Programmer::Group &))); + statusBar()->addWidget(_programmerStatus->widget(), 0, true); + _toolStatus = new ToolStatusWidget(statusBar()); + connect(_toolStatus, SIGNAL(configureToolchain()), SLOT(configureToolchains())); + connect(_toolStatus, SIGNAL(configure()), SLOT(configureProject())); + connect(_toolStatus, SIGNAL(selected(const Tool::Group &)), SLOT(selectTool(const Tool::Group &))); + statusBar()->addWidget(_toolStatus->widget(), 0, true); + +// interface + _mainDock = createDockWidget("main_dock_widget", QPixmap()); + _mainDock->setDockSite(KDockWidget::DockCorner); + _mainDock->setEnableDocking(KDockWidget::DockNone); + setView(_mainDock); + setMainDockWidget(_mainDock); + + KIconLoader loader; + KDockWidget *dock = createDock("project_manager_dock_widget", PURL::icon(PURL::Project), + i18n("Project Manager"), DockPosition(KDockWidget::DockLeft, 20)); + Main::_projectManager = new ProjectManager::View(dock); + connect(Main::_projectManager, SIGNAL(guiChanged()), SLOT(updateGUI())); + dock->setWidget(Main::_projectManager); + + dock = createDock("watch_view_dock_widget", loader.loadIcon("viewmag", KIcon::Small), + i18n("Watch View"), DockPosition("project_manager_dock_widget")); + Main::_watchView = new Register::WatchView(dock); + dock->setWidget(Main::_watchView); + + Main::_editorManager = new EditorManager(_mainDock); + _mainDock->setWidget(Main::_editorManager); + connect(Main::_editorManager, SIGNAL(guiChanged()), SLOT(updateGUI())); + connect(Main::_editorManager, SIGNAL(modified(const PURL::Url &)), Main::_projectManager, SLOT(modified(const PURL::Url &))); + connect(Main::_editorManager, SIGNAL(statusChanged(const QString &)), _editorStatus, SLOT(setText(const QString &))); + + dock = createDock("compile_log_dock_widget", loader.loadIcon("piklab_compile", KIcon::Small), + i18n("Compile Log"), DockPosition(KDockWidget::DockBottom, 80)); + Main::_compileLog = new Compile::LogWidget(dock); + Main::_compileLog->setFocusPolicy(NoFocus); + dock->setWidget(Main::_compileLog); + + dock = createDock("program_log_dock_widget", loader.loadIcon("piklab_burnchip", KIcon::Small), + i18n("Program Log"), DockPosition("compile_log_dock_widget")); + _programLog = new Log::Widget(dock, "program_log"); + _programLog->setFocusPolicy(NoFocus); + dock->setWidget(_programLog); + + dock = createDock("breakpoints_dock_widget", loader.loadIcon("piklab_breakpoint_active", KIcon::Small), + i18n("Breakpoints"), DockPosition("compile_log_dock_widget")); + Main::_breakpointsView = new Breakpoint::View(dock); + Main::_breakpointsView->setFocusPolicy(NoFocus); + dock->setWidget(Main::_breakpointsView); + + dock = createDock("console_dock_widget", loader.loadIcon("konsole", KIcon::Small), + i18n("Konsole"), DockPosition("compile_log_dock_widget")); + Main::_consoleView = new ConsoleView(dock); + dock->setWidget(Main::_consoleView); + +// managers + Programmer::manager = new Programmer::GuiManager(this); + Programmer::manager->setView(_programLog); + connect(Programmer::manager, SIGNAL(actionMessage(const QString &)), _actionStatus, SLOT(setText(const QString &))); + connect(Programmer::manager, SIGNAL(showProgress(bool)), SLOT(showProgress(bool))); + connect(Programmer::manager, SIGNAL(setTotalProgress(uint)), SLOT(setTotalProgress(uint))); + connect(Programmer::manager, SIGNAL(setProgress(uint)), SLOT(setProgress(uint))); + + Debugger::manager = new Debugger::GuiManager; + connect(Debugger::manager, SIGNAL(targetStateChanged()), SLOT(updateGUI())); + connect(Debugger::manager, SIGNAL(statusChanged(const QString &)), _debugStatus, SLOT(setText(const QString &))); + connect(Debugger::manager, SIGNAL(actionMessage(const QString &)), _actionStatus, SLOT(setText(const QString &))); + + Main::_compileManager = new Compile::Manager(this); + Main::_compileManager->setView(Main::_compileLog); + connect(Main::_compileManager, SIGNAL(success()), SLOT(compileSuccess())); + connect(Main::_compileManager, SIGNAL(failure()), SLOT(compileFailure())); + connect(Main::_compileManager, SIGNAL(updateFile(const Compile::FileData &)), + SLOT(updateFile(const Compile::FileData &))); + +// actions + // file actions + KAction *a = KStdAction::openNew(this, SLOT(newSourceFile()), actionCollection()); + a->setText(i18n("&New Source File...")); + (void)new KAction(i18n("New hex File..."), "filenew", 0, this, SLOT(newHexFile()), + actionCollection(), "file_new_hex"); + KStdAction::open(this, SLOT(openFile()), actionCollection()); + KRecentFilesAction *recent = KStdAction::openRecent(this, SLOT(openRecentFile(const KURL &)), actionCollection()); + recent->setMaxItems(20); + recent->loadEntries(kapp->config(), "recent-files"); + (void)new KAction(i18n("Save All"), 0, 0, Main::_editorManager, SLOT(saveAllFiles()), + actionCollection(), "file_save_all"); + KStdAction::close(Main::_editorManager, SLOT(closeCurrentEditor()), actionCollection()); + (void)new KAction(i18n("C&lose All"), 0, 0, Main::_editorManager, SLOT(closeAllEditors()), + actionCollection(), "file_close_all"); + (void)new KAction(i18n("Close All Others"), 0, 0, Main::_editorManager, SLOT(closeAllOtherEditors()), + actionCollection(), "file_closeother"); + KStdAction::quit(this, SLOT(close()), actionCollection()); + + // edit actions + + // view actions + (void)new KAction(i18n("Back"), "back", Qt::ALT + Qt::Key_Left, + Main::_editorManager, SLOT(goBack()), actionCollection(), "history_back"); + (void)new KAction(i18n("Forward"), "forward", Qt::ALT + Qt::Key_Right, + Main::_editorManager, SLOT(goForward()), actionCollection(), "history_forward"); + (void)new KAction(i18n("Switch to..."), 0, Qt::CTRL + Qt::Key_Slash, + Main::_editorManager, SLOT(switchToEditor()), actionCollection(), "file_switchto"); + (void)new KAction(i18n("Switch Header/Implementation"), 0, Qt::SHIFT + Qt::Key_F12, + Main::_editorManager, SLOT(switchHeaderImplementation()), actionCollection(), "view_switch_source"); + (void)new KAction(QString::null, 0, 0, + Debugger::manager, SLOT(toggleBreakpoint()), actionCollection(), "toggle_breakpoint"); + (void)new KAction(QString::null, 0, 0, + Debugger::manager, SLOT(toggleEnableBreakpoint()), actionCollection(), "enable_breakpoint"); + (void)new KAction(i18n("Show disassembly location"), 0, 0, + Debugger::manager, SLOT(showDisassemblyLocation()), actionCollection(), "show_disassembly_location"); + KActionMenu *toolViewsMenu = new KActionMenu( i18n("Tool Views"), 0, "view_tool_views"); + connect(toolViewsMenu->popupMenu(), SIGNAL(aboutToShow()), SLOT(updateToolViewsActions())); + actionCollection()->insert(toolViewsMenu); + a = new KAction(i18n("&Reset Layout"), 0, 0, this, SLOT(resetDockLayout()), actionCollection(), "view_reset_layout"); + toolViewsMenu->insert(a); + toolViewsMenu->popupMenu()->insertSeparator(); + QValueList<DockData>::iterator it; + for(it=_docks.begin(); it!=_docks.end(); ++it) toolViewsMenu->insert((*it).action); + + // project actions + (void)new KAction(i18n("New Project..."), "piklab_createproject", 0, + this, SLOT(newProject()), actionCollection(), "project_new"); + (void)new KAction(i18n("Open Project..."), "piklab_openproject", 0, + this , SLOT(openProject()), actionCollection(), "project_open"); + recent = new KRecentFilesAction(i18n("Open Recent Project"), 0, + this, SLOT(openRecentProject(const KURL &)), actionCollection(), "project_open_recent"); + recent->setMaxItems(20); + recent->loadEntries(kapp->config(), "recent-projects"); + (void)new KAction(i18n("Project Options..."), "configure", 0, + this, SLOT(configureProject()), actionCollection(), "project_options"); + (void)new KAction(i18n("Close Project"), "fileclose", 0, + this, SLOT(closeProject()), actionCollection(), "project_close"); + (void)new KAction(i18n("Add Source File..."), "piklab_addfile", 0, + Main::_projectManager, SLOT(insertSourceFiles()), actionCollection(), "project_add_source_file"); + (void)new KAction(i18n("Add Object File..."), "piklab_addfile", 0, + Main::_projectManager, SLOT(insertObjectFiles()), actionCollection(), "project_add_object_file"); + (void)new KAction(i18n("Add Current File"), "piklab_addcurrentfile", 0, + Main::_projectManager, SLOT(insertCurrentFile()), actionCollection(), "project_add_current_file"); + + // build actions + (void)new KAction(i18n("&Build Project"), "piklab_compile", Qt::Key_F8, + this, SLOT(buildProject()), actionCollection(), "build_build_project"); + (void)new KAction(i18n("&Compile File"), 0, Qt::SHIFT + Qt::Key_F8, + this, SLOT(compileFile()), actionCollection(), "build_compile_file"); + (void)new KAction(i18n("Clean"), "trashcan_empty", 0, + this, SLOT(cleanBuild()), actionCollection(), "build_clean"); + (void)new KAction(i18n("Stop"), "stop", 0, + this, SLOT(stopBuild()), actionCollection(), "build_stop"); + + // programmer actions + (void)new KAction(i18n("&Connect"), "connect_creating", 0, + Programmer::manager, SLOT(connectDevice()), actionCollection(), "prog_connect"); + (void)new KToggleAction(i18n("Device Power"), "piklab_power", 0, + Programmer::manager, SLOT(toggleDevicePower()), actionCollection(), "prog_power"); + (void)new KAction(i18n("&Disconnect"), "connect_no", 0, + Programmer::manager, SLOT(disconnectDevice()), actionCollection(), "prog_disconnect"); + (void)new KAction(i18n("&Program"), "piklab_burnchip", Qt::SHIFT + Qt::Key_F5, + this , SLOT(program()), actionCollection(), "prog_program"); + (void)new KAction(i18n("&Verify"), "piklab_verifychip", Qt::SHIFT + Qt::Key_F6, + this , SLOT(verify()), actionCollection(), "prog_verify"); + (void)new KAction(i18n("&Read"), "piklab_readchip", Qt::SHIFT + Qt::Key_F7, + this , SLOT(read()), actionCollection(), "prog_read"); + (void)new KAction(i18n("&Erase"), "piklab_erasechip", 0, + this, SLOT(erase()), actionCollection(), "prog_erase"); + (void)new KAction(i18n("&Blank Check"), "piklab_blankcheck", 0, + this, SLOT(blankCheck()), actionCollection(), "prog_blank_check"); + (void)new KAction(i18n("&Run"), "launch", Qt::SHIFT + Qt::Key_F9, + Programmer::manager, SLOT(run()), actionCollection(), "prog_run"); + (void)new KAction(i18n("&Stop"), "piklab_stop", 0, + Programmer::manager, SLOT(halt()), actionCollection(), "prog_stop"); + (void)new KAction(i18n("R&estart"), "piklab_restart", 0, + Programmer::manager, SLOT(restart()), actionCollection(), "prog_restart"); + (void)new KAction(i18n("&Advanced..."), 0, 0, + Programmer::manager , SLOT(showAdvancedDialog()), actionCollection(), "prog_advanced"); + (void)new KAction(i18n("Settings..."), "configure", 0, + this , SLOT(showProgrammerSettings()), actionCollection(), "prog_settings"); + + // debugger actions + (void)new KAction(i18n("&Start"), "launch", Qt::SHIFT + Qt::Key_F9, + Programmer::manager, SLOT(restart()), actionCollection(), "debug_start"); + (void)new KAction(i18n("&Run"), "piklab_run", Qt::SHIFT + Qt::Key_F9, + Programmer::manager, SLOT(run()), actionCollection(), "debug_run"); + (void)new KAction(i18n("&Step"), "piklab_debug_step", 0, + Programmer::manager, SLOT(step()), actionCollection(), "debug_next"); + //(void)new KAction(i18n("Step &In"), "piklab_debug_stepin", + // 0, this, SLOT(debugStepIn()), actionCollection(), "debug_step_in"); + //(void)new KAction(i18n("Step &Out"), "piklab_debug_stepout", + // 0, this, SLOT(debugStepOut()), actionCollection(), "debug_step_out"); + (void)new KAction(i18n("&Break<Translators: it is the verb>", "&Halt"), "piklab_debughalt", 0, + Programmer::manager, SLOT(halt()), actionCollection(), "debug_halt"); + (void)new KAction(i18n("&Disconnect/Stop"), "piklab_stop", 0, + Programmer::manager, SLOT(disconnectDevice()), actionCollection(), "debug_stop"); + (void)new KAction(i18n("R&eset"), "piklab_restart", 0, + Programmer::manager, SLOT(restart()), actionCollection(), "debug_reset"); + (void)new KAction(i18n("Show Program Counter"), "piklab_program_counter", 0, + Debugger::manager, SLOT(showPC()), actionCollection(), "debug_show_pc"); + (void)new KAction(i18n("Clear All Breakpoints"), "remove", 0, + Debugger::manager, SLOT(clearBreakpoints()), actionCollection(), "debug_clear_breakpoints"); + (void)new KAction(i18n("Settings..."), "configure", 0, + this , SLOT(showDebuggerSettings()), actionCollection(), "debug_settings"); + + // tools + (void)new KAction(i18n("&Pikloops..."), 0, 0, + this , SLOT(runPikloops()), actionCollection(), "tools_pikloops"); + (void)new KAction(i18n("&Find Files..."), "find", 0, + this , SLOT(runKfind()), actionCollection(), "tools_kfind"); + (void)new KAction(i18n("&Device Information..."), "info", 0, + this , SLOT(showDeviceInfo()), actionCollection(), "tools_device_information"); + (void)new KAction(i18n("&Config Generator..."), 0, 0, + this , SLOT(configGenerator()), actionCollection(), "tools_config_generator"); + (void)new KAction(i18n("&Template Generator..."), 0, 0, + this , SLOT(templateGenerator()), actionCollection(), "tools_template_generator"); + + // settings actions + (void)new KAction(i18n("Configure Toolchains..."), 0, 0, + this, SLOT(configureToolchains()), actionCollection(), "options_configure_toolchains"); + (void)KStdAction::preferences(this, SLOT(configure()), actionCollection()); + + // help + (void)new KAction(i18n("Report Bug..."), "likeback_bug", 0, + LikeBack::instance(), SLOT(iFoundABug()), actionCollection(), "help_report_bug_piklab"); + + setupGUI(); + readDockConfig(); + + // LikeBack buttons + menuBar()->insertItem(new QLabel(menuBar())); // #### first widget is put left-most... + MenuBarButton *button = new MenuBarButton("likeback_like", menuBar()); + QToolTip::add(button, i18n("I like...")); + connect(button, SIGNAL(clicked()), LikeBack::instance(), SLOT(iLike())); + menuBar()->insertItem(button); + button = new MenuBarButton("likeback_dislike", menuBar()); + QToolTip::add(button, i18n("I do not like...")); + connect(button, SIGNAL(clicked()), LikeBack::instance(), SLOT(iDoNotLike())); + menuBar()->insertItem(button); + button = new MenuBarButton("likeback_bug", menuBar()); + QToolTip::add(button, i18n("I found a bug...")); + connect(button, SIGNAL(clicked()), LikeBack::instance(), SLOT(iFoundABug())); + menuBar()->insertItem(button); + button = new MenuBarButton("configure", menuBar()); + QToolTip::add(button, i18n("Configure email...")); + connect(button, SIGNAL(clicked()), LikeBack::instance(), SLOT(askEMail())); + menuBar()->insertItem(button); + button = new MenuBarButton("help", menuBar()); + connect(button, SIGNAL(clicked()), LikeBack::instance(), SLOT(showWhatsThisMessage())); + menuBar()->insertItem(button); + + QTimer::singleShot(0, this, SLOT(initialLoading())); +} + +MainWindow::~MainWindow() +{} + +void MainWindow::readDockConfig() +{ + KDockMainWindow::readDockConfig(kapp->config(), "dock_config"); + + // if there is a new dock: it is not displayed by default... + QMap<QString, QString> entries = kapp->config()->entryMap("dock_config"); + QValueList<DockData>::iterator it; + for(it=_docks.begin(); it!=_docks.end(); ++it) { + QMap<QString, QString>::const_iterator eit; + for(eit=entries.begin(); eit!=entries.end(); ++eit) + if ( eit.key().startsWith((*it).dock->name()) ) break; + if ( eit==entries.end() ) initDockPosition(*it); + } + + // readDockConfig also restore the names/tooltips: what if a new version of the application changes these names... + for(it=_docks.begin(); it!=_docks.end(); ++it) (*it).dock->setTabPageLabel((*it).title); + QApplication::postEvent(this, new QEvent(QEvent::CaptionChange)); +} + +void MainWindow::initialLoading() +{ + ::BusyCursor bc; + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + if ( args->count()!=0 ) { // opened urls provided on the command line + for (int i = 0; i<args->count(); i++) { + PURL::Url url(args->url(i)); + if ( url.fileType()==PURL::Project ) { + if ( Main::_projectManager->project()==0 ) Main::_projectManager->openProject(url); + } else Main::_editorManager->openEditor(url); + } + } else { // otherwise reopen last project/files + Main::_projectManager->openProject(GlobalConfig::openedProject()); + PURL::UrlList files = GlobalConfig::openedFiles(); + PURL::UrlList::const_iterator it = files.begin(); + for (; it!=files.end(); ++it) Main::_editorManager->openEditor(*it); + } + updateGUI(); +} + +void MainWindow::openRecentFile(const KURL &kurl) +{ + Main::_editorManager->openFile(PURL::Url(kurl)); +} + +void MainWindow::configureToolbar() +{ + saveMainWindowSettings(KGlobal::config(), "MainWindow"); + KEditToolbar dlg(actionCollection()); + connect(&dlg, SIGNAL(newToolbarConfig()), SLOT(applyToolbarSettings())); + dlg.exec(); +} + +void MainWindow::applyToolbarSettings() +{ + createGUI(); + applyMainWindowSettings(KGlobal::config(), "MainWindow"); +} + +void MainWindow::configure(ConfigCenter::Type showType) +{ + stopOperations(); + ConfigCenter dialog(showType, this); + dialog.exec(); + Programmer::manager->clear(); + updateGUI(); + Debugger::manager->update(true); +} + +void MainWindow::configureToolchains() +{ + stopOperations(); + ToolchainsConfigCenter dialog(Main::toolGroup(), this); + dialog.exec(); + Programmer::manager->clear(); + updateGUI(); + Debugger::manager->update(true); +} + +void MainWindow::selectProgrammer(const Programmer::Group &group) +{ + if ( group.name()==Main::programmerGroup().name() ) return; + bool debugInitialized = Debugger::manager->coff(); + stopOperations(); + GlobalConfig::writeProgrammerGroup(group); + Programmer::manager->clear(); + updateGUI(); + if (debugInitialized) Debugger::manager->init(); + else Debugger::manager->update(true); +} + +void MainWindow::selectTool(const Tool::Group &group) +{ + if ( group.name()==Compile::Config::toolGroup(Main::project()).name() ) return; + bool debugInitialized = Debugger::manager->coff(); + stopOperations(); + Compile::Config::setToolGroup(Main::project(), group); + updateGUI(); + if (debugInitialized) Debugger::manager->init(); + else Debugger::manager->update(true); +} + +void MainWindow::setDevice(const QString &device) +{ + if ( device==i18n(Device::AUTO_DATA.label) ) Compile::Config::setDevice(Main::project(), Device::AUTO_DATA.name); + else Compile::Config::setDevice(Main::project(), device); + updateGUI(); +} + +void MainWindow::showDeviceInfo() +{ + DeviceChooser::Dialog d(Main::device(), (Main::project() ? DeviceChooser::Choose : DeviceChooser::ChooseWithAuto), this); + if ( d.exec() ) { + setDevice(d.device()); + updateGUI(); + } +} + +void MainWindow::configGenerator() +{ + PURL::FileType ftype = (Main::currentEditor() ? Main::currentEditor()->fileType() : PURL::Nb_FileTypes); + PURL::SourceFamily family = (ftype!=PURL::Nb_FileTypes ? ftype.data().sourceFamily : PURL::SourceFamily(PURL::SourceFamily::Nb_Types)); + PURL::ToolType type = (family!=PURL::SourceFamily::Nb_Types ? family.data().toolType : PURL::ToolType(PURL::ToolType::Assembler)); + ConfigGenerator dialog(this); + dialog.set(Main::deviceData(), Main::toolGroup(), type); + dialog.exec(); +} + +void MainWindow::templateGenerator() +{ + PURL::FileType ftype = (Main::currentEditor() ? Main::currentEditor()->fileType() : PURL::Nb_FileTypes); + PURL::SourceFamily family = (ftype!=PURL::Nb_FileTypes ? ftype.data().sourceFamily : PURL::SourceFamily(PURL::SourceFamily::Nb_Types)); + PURL::ToolType type = (family!=PURL::SourceFamily::Nb_Types ? family.data().toolType : PURL::ToolType(PURL::ToolType::Assembler)); + TemplateGenerator dialog(this); + dialog.set(Main::deviceData(), Main::toolGroup(), type); + dialog.exec(); +} + +bool MainWindow::queryClose() +{ + if ( !stopOperations() ) return false; + Main::setState(Main::Closing); + // save list of opened editors + PURL::UrlList toSave; + const PURL::UrlList files = Main::_editorManager->files(); + PURL::UrlList::const_iterator it; + for (it=files.begin(); it!=files.end(); ++it) + if ( !Main::_projectManager->isExternalFile(*it) ) toSave.append(*it); + GlobalConfig::writeOpenedFiles(toSave); + // close editors + if ( !Main::_editorManager->closeAllEditors() ) { + Main::setState(Main::Idle); + return false; + } + // save other settings + ::BusyCursor bc; + writeDockConfig(kapp->config(), "dock_config"); + static_cast<KRecentFilesAction *>(Main::action("project_open_recent"))->saveEntries(kapp->config(), "recent-projects"); + static_cast<KRecentFilesAction *>(Main::action("file_open_recent"))->saveEntries(kapp->config(), "recent-files"); + GlobalConfig::writeOpenedProject(Main::project() ? Main::project()->url() : PURL::Url()); + if ( Main::project() ) Main::_projectManager->closeProject(); + return true; +} + +void MainWindow::newSourceFile() +{ + NewFileDialog dialog(Main::project(), this); + if ( dialog.exec()!=QDialog::Accepted ) return; + if ( !dialog.url().exists() && !dialog.url().create(*Main::_compileLog) ) return; + Main::_editorManager->openEditor(dialog.url()); + if ( dialog.addToProject() ) Main::_projectManager->insertFile(dialog.url()); +} + +void MainWindow::newHexFile() +{ + if ( Main::device()==Device::AUTO_DATA.name ) { + MessageBox::sorry(i18n("You need to specify a device to create a new hex file."), Log::Show); + return; + } + QString s; + for (uint i=0; true; i++) { + s = i18n("Hex") + (i==0 ? QString::null : QString::number(i)); + if ( Main::_editorManager->findEditor(s)==0 ) break; + } + HexEditor *editor = new HexEditor(s, Main::_editorManager); + editor->memoryRead(); + Main::_editorManager->addEditor(editor); +} + +bool MainWindow::openFile() +{ + QString filter; + filter += PURL::sourceFilter(PURL::SimpleFilter); + filter += "\n" + PURL::filter(PURL::Hex); + filter += "\n" + PURL::projectFilter(PURL::SimpleFilter); + filter += "\n*|" + i18n("All Files"); + PURL::Url url = PURL::getOpenUrl(":open_file", filter, this ,i18n("Open File")); + if ( url.fileType()==PURL::Project || url.fileType()==PURL::PikdevProject ) { + stopOperations(); + if ( !Main::_projectManager->openProject(url) ) return false; + updateGUI(); + return true; + } + return Main::_editorManager->openFile(url); +} + +void MainWindow::updateGUI() +{ + bool idle = ( Main::_state==Main::Idle ); + switch (Main::_state) { + case Main::Closing: return; + case Main::Idle: + showProgress(false); + break; + case Main::Compiling: + _actionStatus->setText(Main::_compileManager->label()); + showProgress(true); + makeWidgetDockVisible(Main::_compileLog); + break; + case Main::Programming: + makeWidgetDockVisible(_programLog); + break; + } + + // update editor actions + Main::_editorManager->updateTitles(); + Main::action("file_save_all")->setEnabled(Main::currentEditor()); + Main::action("file_close")->setEnabled(Main::currentEditor()); + Main::action("file_close_all")->setEnabled(Main::currentEditor()); + Main::action("file_closeother")->setEnabled(Main::_editorManager->nbEditors()>1); + Main::action("options_configure")->setEnabled(idle); + PURL::FileType currentType = (Main::currentEditor() ? Main::currentEditor()->fileType() : PURL::Nb_FileTypes); + bool isSource = (currentType==PURL::Nb_FileTypes ? false : currentType.data().group==PURL::Source); + bool isHeader = (currentType==PURL::Nb_FileTypes ? false : currentType.data().group==PURL::Header); + Main::action("view_switch_source")->setEnabled(isSource || isHeader); + Main::action("history_back")->setEnabled(Main::editorManager().history().hasBack()); + Main::action("history_forward")->setEnabled(Main::editorManager().history().hasForward()); + Main::action("show_disassembly_location")->setEnabled(Debugger::manager->coff()!=0 && (isSource || isHeader)); + + // update project + bool inProject = ( Main::currentEditor() && (currentType==PURL::Nb_FileTypes || Main::currentEditor()->url().isEmpty() || Main::_projectManager->contains(Main::currentEditor()->url())) ); + if ( Main::project()==0 && !inProject ) { + if ( Main::currentEditor()==0 ) Main::_projectManager->closeProject(); + else if ( isSource ) Main::_projectManager->setStandalone(Main::currentEditor()->url(), currentType); + else { + PURL::FileType type; + PURL::Url purl = Main::_projectManager->standaloneGenerator(Main::currentEditor()->url(), type); + if ( type!=PURL::Nb_FileTypes ) Main::_projectManager->setStandalone(purl, type); + else if ( currentType==PURL::Hex ) Main::_projectManager->setStandalone(purl, PURL::Hex); + } + } + if ( Main::currentEditor() ) Main::_projectManager->select(Main::currentEditor()); + + // update project actions + Main::action("project_new")->setEnabled(idle); + Main::action("project_open")->setEnabled(idle); + Main::action("project_close")->setEnabled(Main::project() && idle); + Main::action("project_options")->setEnabled(Main::project() && idle); + Main::action("project_add_source_file")->setEnabled(Main::project() && idle); + Main::action("project_add_object_file")->setEnabled(Main::project() && idle); + Main::action("project_add_current_file")->setEnabled(Main::project() && !inProject && idle && isSource); + + // update build actions + static_cast<PopupButton *>(_toolStatus->widget())->setText(" " + Main::toolGroup().label() + " "); + bool hexProject = ( Main::_projectManager->projectUrl().fileType()==PURL::Hex ); + bool customTool = Main::toolGroup().isCustom(); + Main::action("build_build_project")->setEnabled((Main::project() || (inProject && !hexProject) ) && idle); + PURL::Url selected = Main::_projectManager->selectedUrl(); + bool isSelectedSource = ( !selected.isEmpty() && selected.data().group==PURL::Source ); + Main::action("build_compile_file")->setEnabled(!hexProject && (isSource || isSelectedSource) && idle && !customTool); + Main::action("build_clean")->setEnabled((Main::project() || inProject) && idle && !customTool); + Main::action("build_stop")->setEnabled(Main::_state==Main::Compiling); + + // update programmer status + PortType ptype = Programmer::GroupConfig::portType(Main::programmerGroup()); + static_cast<PopupButton *>(_programmerStatus->widget())->setText(" " + Main::programmerGroup().statusLabel(ptype) + " "); + QFont f = font(); + bool supported = (Main::deviceData() ? Main::programmerGroup().isSupported(Main::deviceData()->name()) : false); + f.setItalic(!supported); + _programmerStatus->widget()->setFont(f); + bool isProgrammer = ( Main::programmerGroup().properties() & ::Programmer::Programmer ); + PURL::Url purl = Main::_projectManager->projectUrl(); + bool hasHex = ( currentType==PURL::Hex || Main::_projectManager->contains(purl.toFileType(PURL::Hex)) ); + Main::action("prog_connect")->setEnabled(isProgrammer && idle); + Main::action("prog_read")->setEnabled(isProgrammer && idle); + Main::action("prog_program")->setEnabled(isProgrammer && hasHex && idle); + Main::action("prog_verify")->setEnabled(isProgrammer && hasHex && idle); + Main::action("prog_erase")->setEnabled(isProgrammer && idle); + Main::action("prog_blank_check")->setEnabled(isProgrammer && idle); + Programmer::State pstate = (Main::programmer() ? Main::programmer()->state() : Programmer::NotConnected); + static_cast<KToggleAction *>(Main::action("prog_power"))->setEnabled(isProgrammer && idle && pstate!=Programmer::NotConnected); + Main::action("prog_disconnect")->setEnabled(isProgrammer && idle && pstate!=Programmer::NotConnected); + bool isDebugger = ( Main::programmerGroup().properties() & ::Programmer::Debugger ); + bool resetAvailable = ( Main::programmerGroup().properties() & Programmer::CanReleaseReset ); + Main::action("prog_run")->setEnabled(idle && resetAvailable && !isDebugger && pstate!=Programmer::Running); + Main::action("prog_stop")->setEnabled(idle && !isDebugger && pstate==Programmer::Running); + Main::action("prog_restart")->setEnabled(idle && !isDebugger && pstate==Programmer::Running); + const Programmer::GroupUI *pgui = static_cast<const Programmer::GroupUI *>(Main::programmerGroup().gui()); + Main::action("prog_advanced")->setEnabled(idle && pgui->hasAdvancedDialog()); + + // update debugger status + Debugger::manager->updateDevice(); + Main::action("debug_start")->setEnabled(idle && isDebugger && pstate!=Programmer::Running && pstate!=Programmer::Halted); + Main::action("debug_run")->setEnabled(idle && isDebugger && pstate!=Programmer::Running && !Debugger::manager->isStepping() ); + Main::action("debug_halt")->setEnabled(idle && isDebugger && (pstate==Programmer::Running || Debugger::manager->isStepping()) ); + Main::action("debug_stop")->setEnabled(idle && isDebugger && (pstate==Programmer::Running || pstate==Programmer::Halted)); + Main::action("debug_next")->setEnabled(idle && isDebugger && pstate!=Programmer::Running); + Main::action("debug_reset")->setEnabled(idle && isDebugger && (pstate==Programmer::Running || pstate==Programmer::Halted)); + Main::action("debug_show_pc")->setEnabled(idle && isDebugger && Debugger::manager->coff()!=0 && Debugger::manager->pc().isInitialized() ); + + Main::_projectManager->updateGUI(); + + // caption + QString caption; + if ( Main::project() ) caption += Main::project()->name(); + if ( Main::currentEditor() ) { + if ( Main::project() ) caption += " - "; + caption += Main::currentEditor()->url().filepath(); + } + setCaption(KApplication::kApplication()->makeStdCaption(caption)); + + emit stateChanged(); +} + +void MainWindow::updateToolViewsActions() +{ + QValueList<DockData>::iterator it; + for(it=_docks.begin(); it!=_docks.end(); ++it) (*it).action->setChecked((*it).dock->mayBeHide()); +} + +void MainWindow::initDockPosition(const DockData &ddata) +{ + const DockPosition &pos = ddata.position; + ddata.dock->manualDock(manager()->getDockWidgetFromName(pos.parent), pos.pos, pos.space); +} + +void MainWindow::resetDockLayout() +{ + QValueList<DockData>::iterator it; + for (it=_docks.begin(); it!=_docks.end(); ++it) initDockPosition(*it); +} + +void MainWindow::toggleToolView(QWidget *widget) +{ + static_cast<KDockWidget *>(widget)->changeHideShowState(); +} + +void MainWindow::runKfind() +{ + if (_kfindProcess) return; + _kfindProcess = new ::Process::StringOutput; + QString path; + PURL::Url url = Main::projectManager().projectUrl(); + if ( !url.isEmpty() ) path = url.path(); + _kfindProcess->setup("kfind", path, false); + connect(_kfindProcess, SIGNAL(done(int)), SLOT(kfindDone())); + if ( !_kfindProcess->start(0) ) + MessageBox::sorry(i18n("Could not run \"kfind\""), Log::Show); +} + +void MainWindow::kfindDone() +{ + delete _kfindProcess; + _kfindProcess = 0; +} + +void MainWindow::runPikloops() +{ + if (_pikloopsProcess) return; + _pikloopsProcess = new ::Process::StringOutput; + _pikloopsProcess->setup("pikloops", QStringList(), false); + connect(_pikloopsProcess, SIGNAL(done(int)), SLOT(pikloopsDone())); + if ( !_pikloopsProcess->start(0) ) + MessageBox::detailedSorry(i18n("Could not run \"pikloops\""), i18n("The Pikloops utility (%1) is not installed in your system.").arg("http://pikloops.sourceforge.net"), Log::Show); +} + +void MainWindow::pikloopsDone() +{ + delete _pikloopsProcess; + _pikloopsProcess = 0; +} + +//----------------------------------------------------------------------------- +void MainWindow::compileFile() +{ + Editor *e = Main::currentEditor(); + if ( e && e->isModified() ) e->save(); // buffer is systematically saved + stopOperations(); + Main::_compileLog->clear(); + PURL::Url url = (e ? e->url() : Main::_projectManager->selectedUrl()); + bool generated = (e ? Main::_projectManager->isExternalFile(url) : false); + if ( Main::project()==0 || !generated ) Main::_projectManager->removeExternalFiles(); + url = (!generated ? url : Main::_projectManager->projectUrl()); + if ( Main::_compileManager->compileFile(Compile::TodoItem(url, generated)) ) Main::setState(Main::Compiling); + else compileFailure(); +} + +void MainWindow::buildProject() +{ + if ( Main::project()==0 ) { + compileFile(); + return; + } + // save modified buffers + PURL::UrlList files = Main::project()->absoluteFiles(); + PURL::UrlList::const_iterator it; + for (it=files.begin(); it!=files.end(); ++it) { + // save modified editors + Editor *e = Main::_editorManager->findEditor(*it); + if ( e && e->isModified() ) e->save(); + } + bool tmp = _forceProgramAfterBuild; + stopOperations(); + _forceProgramAfterBuild = tmp; + Main::_compileLog->clear(); + Main::_projectManager->removeExternalFiles(); + Compile::LinkType ltype = (Main::programmerGroup().name()=="icd2_debugger" ? Compile::Icd2Linking : Compile::NormalLinking); + if ( Main::_compileManager->buildProject(ltype) ) Main::setState(Main::Compiling); + else compileFailure(); +} + +void MainWindow::compileFailure() +{ + _forceProgramAfterBuild = false; + Main::setState(Main::Idle); +} + +void MainWindow::compileSuccess() +{ + if ( !Main::_compileManager->compileOnly() ) { + Main::_projectManager->setModified(false); + if ( Main::project()->outputType()==Tool::OutputType::Executable ) { + if ( Debugger::manager->init() ) { + const QStringList &included = Debugger::manager->coff()->filenames(); + QStringList::const_iterator it; + for (it=included.begin(); it!=included.end(); ++it) { + PURL::Directory dir = (Main::project() ? Main::project()->directory() : Main::projectManager().projectUrl().directory()); + PURL::Url url = PURL::Url::fromPathOrUrl(*it).toAbsolute(dir); + if ( !url.exists() ) continue; + Main::_projectManager->addExternalFile(url, ProjectManager::Included); + } + } + if ( _forceProgramAfterBuild || readConfigEntry(BaseGlobalConfig::ProgramAfterBuild).toBool() ) program(); + } + } + _forceProgramAfterBuild = false; + Main::setState(Main::Idle); +} + +void MainWindow::updateFile(const Compile::FileData &fdata) +{ + if ( fdata.actions & Compile::InProject ) { + if ( fdata.actions & Compile::Generated ) Main::_projectManager->addExternalFile(fdata.url, ProjectManager::Generated); + else if ( fdata.actions & Compile::Included ) Main::_projectManager->addExternalFile(fdata.url, ProjectManager::Included); + else Q_ASSERT(false); + } + if ( fdata.actions & Compile::Show ) { + Editor *e = Main::_editorManager->openEditor(fdata.url); + if (e) e->setReadOnly(true); + } +} + +void MainWindow::cleanBuild() +{ + stopOperations(); + Main::_compileLog->clear(); + if ( Main::project() ) { + Compile::LinkType ltype = (Main::programmerGroup().name()=="icd2_debugger" ? Compile::Icd2Linking : Compile::NormalLinking); + Main::_compileManager->cleanProject(ltype); + } else { + PURL::FileType type; + PURL::Url url = Main::_projectManager->standaloneGenerator(Main::currentEditor()->url(), type); + Main::_compileManager->cleanFile(url); + } + Main::_projectManager->removeExternalFiles(); +} + +void MainWindow::stopBuild() +{ + Main::_compileManager->kill(); +} + +//----------------------------------------------------------------------------- +void MainWindow::keyPressEvent(QKeyEvent *e) +{ + if ( e->key()==Key_Escape ) stopOperations(); +} + +bool MainWindow::stopOperations() +{ + if ( Main::_state==Main::Programming ) { + _programLog->log(Log::LineType::Warning, i18n("Programming in progress. Cannot be aborted.")); + return false; + } + stopBuild(); + Programmer::manager->stop(); + Debugger::manager->clear(); + return true; +} + +void MainWindow::newProject() +{ + stopOperations(); + Main::_projectManager->newProject(); + updateGUI(); + Main::_compileLog->clear(); +} + +void MainWindow::openProject() +{ + stopOperations(); + Main::_projectManager->openProject(); + updateGUI(); + Main::_compileLog->clear(); +} + +void MainWindow::openRecentProject(const KURL &url) +{ + stopOperations(); + Main::_projectManager->openProject(PURL::Url(url)); + updateGUI(); + Main::_compileLog->clear(); +} + +void MainWindow::configureProject() +{ + stopOperations(); + if ( Main::project()==0 ) configure(ConfigCenter::Standalone); + else Main::_projectManager->editProject(); + updateGUI(); +} + +void MainWindow::closeProject() +{ + stopOperations(); + Main::_projectManager->closeProject(); + updateGUI(); + Main::_compileLog->clear(); +} + +//---------------------------------------------------------------------------- +HexEditor *MainWindow::getHexEditor() +{ + if ( Main::_projectManager->isModified() || Main::_projectManager->needsRecompile() ) { + MessageBox::Result res = MessageBox::Yes; + if ( !readConfigEntry(BaseGlobalConfig::AutoRebuildModified).toBool() ) { + res = MessageBox::questionYesNoCancel(i18n("The project hex file may not be up-to-date since some project files have been modified."), + i18n("Recompile First"), i18n("Continue Anyway")); + if ( res==MessageBox::Cancel ) return 0; + } + if ( res==MessageBox::Yes ) { + _forceProgramAfterBuild = true; + buildProject(); + return 0; + } + } + if ( Main::currentEditor() && Main::currentEditor()->fileType()==PURL::Hex ) + return static_cast<HexEditor *>(Main::currentEditor()); + PURL::Url purl = Main::_projectManager->projectUrl(); + HexEditor *editor = static_cast<HexEditor *>(Main::_editorManager->openEditor(purl.toFileType(PURL::Hex))); + if ( editor==0 ) return 0; + editor->setReadOnly(true); + return editor; +} + +void MainWindow::erase() +{ + Programmer::manager->erase(Device::MemoryRange()); +} + +void MainWindow::blankCheck() +{ + Programmer::manager->blankCheck(Device::MemoryRange()); +} + +void MainWindow::program() +{ + HexEditor *editor = getHexEditor(); + if ( editor==0 ) return; + if ( Main::programmerGroup().isDebugger() && !Main::_projectManager->contains(editor->url()) ) { + MessageBox::sorry(i18n("It is not possible to start a debugging session with an hex file not generated with the current project."), Log::Show); + return; + } + Programmer::manager->program(*editor->memory(), Device::MemoryRange()); +} + +void MainWindow::verify() +{ + HexEditor *editor = getHexEditor(); + if ( editor==0 ) return; + Programmer::manager->verify(*editor->memory(), Device::MemoryRange()); +} + +void MainWindow::read() +{ + QString s = i18n("Read"); + Editor *e = Main::_editorManager->findEditor(s); + if (e) Main::_editorManager->closeEditor(e, true); + HexEditor *editor = new HexEditor(s, Main::_editorManager); + editor->setDevice(); + if ( Programmer::manager->read(*editor->memory(), Device::MemoryRange()) ) { + editor->memoryRead(); + Main::_editorManager->addEditor(editor); + } else delete editor; +} + +void MainWindow::showProgress(bool show) +{ + if (show) { + BusyCursor::start(); + _actionStatus->show(); + _actionProgress->show(); + } else { + BusyCursor::stop(); + _actionStatus->hide(); + _actionProgress->hide(); + } +} + +void MainWindow::setTotalProgress(uint nb) +{ + //KIO::Job *job = new KIO::SimpleJob(KURL(), 0, 0, false); + //int id = Observer::self()->newJob(job, true); + //Observer::self()->slotTotalSize(job, total); + //Observer::self()->slotInfoMessage(job, "test"); + //qDebug("set total steps: %i", total); + _actionProgress->setTotalSteps(nb); + _actionProgress->setProgress(0); + QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput); // #### DANGER !!!! +} + +void MainWindow::setProgress(uint nb) +{ + _actionProgress->setProgress(nb); + QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput); // #### DANGER !!!! +} diff --git a/src/libgui/toplevel.h b/src/libgui/toplevel.h new file mode 100644 index 0000000..11a4316 --- /dev/null +++ b/src/libgui/toplevel.h @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * Copyright (C) 2003-2004 Alain Gibaud <alain.gibaud@free.fr> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef TOPLEVEL_H +#define TOPLEVEL_H + +#include <qlabel.h> +#include <qprogressbar.h> +#include <kdockwidget.h> + +#include "config_center.h" +#include "tools/list/compile_process.h" +#include "toplevel_ui.h" +namespace Programmer { class Group; } +namespace Tool { class Group; } +class ConfigGenerator; +class HexEditor; +namespace Process { class Base; } + +class MainWindow : public KDockMainWindow +{ +Q_OBJECT +public: + MainWindow(); + virtual ~MainWindow(); + void setDevice(const QString &device); + +public slots: + void newSourceFile(); + void newProject(); + void openProject(); + void buildProject(); + void cleanBuild(); + void configure(ConfigCenter::Type showType = ConfigCenter::General); + void configureProject(); + void showDeviceInfo(); + void runPikloops(); + void runKfind(); + void configGenerator(); + void templateGenerator(); + void updateGUI(); + +private slots: + void newHexFile(); + bool openFile(); + void openRecentFile(const KURL &url); + + void compileFile(); + void compileSuccess(); + void compileFailure(); + void updateFile(const Compile::FileData &data); + void stopBuild(); + + void erase(); + void blankCheck(); + void program(); + void verify(); + void read(); + void showProgress(bool show); + void setTotalProgress(uint nbSteps); + void setProgress(uint nbSteps); + + void applyToolbarSettings(); + void configureToolbar(); + void configureToolchains(); + void configureProgrammer() { configure(ConfigCenter::ProgSelect); } + void showProgrammerSettings() { configure(ConfigCenter::ProgOptions); } + void showDebuggerSettings() { configure(ConfigCenter::DebugOptions); } + void selectProgrammer(const Programmer::Group &group); + void selectTool(const Tool::Group &group); + + void updateToolViewsActions(); + void resetDockLayout(); + void toggleToolView(QWidget *widget); + + void pikloopsDone(); + void kfindDone(); + + void openRecentProject(const KURL &url); + void closeProject(); + + void initialLoading(); + +signals: + void stateChanged(); + +private: + Log::Widget *_programLog; + QLabel *_actionStatus, *_debugStatus, *_editorStatus; + ProgrammerStatusWidget *_programmerStatus; + ToolStatusWidget *_toolStatus; + QProgressBar *_actionProgress; + ConfigGenerator *_configGenerator; + ::Process::Base *_pikloopsProcess, *_kfindProcess; + bool _forceProgramAfterBuild; + + class DockPosition { + public: + DockPosition() {} + DockPosition(const QString &pparent) : parent(pparent), pos(KDockWidget::DockCenter), space(0) {} + DockPosition(KDockWidget::DockPosition ppos, uint pspace) : parent("main_dock_widget"), pos(ppos), space(pspace) {} + QString parent; + KDockWidget::DockPosition pos; + uint space; + }; + class DockData { + public: + ViewMenuAction *action; + KDockWidget *dock; + QString title; + DockPosition position; + }; + QValueList<DockData> _docks; + KDockWidget *_mainDock; + + HexEditor *getHexEditor(); + virtual bool queryClose(); + bool stopOperations(); + void cleanBuild(bool singleFile); + virtual void keyPressEvent(QKeyEvent *e); + void readDockConfig(); + KDockWidget *createDock(const QString &name, const QPixmap &icon, const QString &title, const DockPosition &position); + void initDockPosition(const DockData &ddata); +}; + +#endif diff --git a/src/libgui/toplevel_ui.cpp b/src/libgui/toplevel_ui.cpp new file mode 100644 index 0000000..5e8db32 --- /dev/null +++ b/src/libgui/toplevel_ui.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "toplevel_ui.h" + +#include <qstyle.h> +#include <kiconloader.h> + +#include "progs/list/prog_list.h" +#include "tools/list/tool_list.h" + +//---------------------------------------------------------------------------- +ProgrammerStatusWidget::ProgrammerStatusWidget(QWidget *parent) + : QObject(parent), KeyPopupButton<QString>(parent) +{ + connect(widget(), SIGNAL(activated(int)), SLOT(activatedSlot(int))); + widget()->appendAction(i18n("Configure..."), "configure", this, SIGNAL(configure())); + widget()->appendSeparator(); + Programmer::Lister::ConstIterator it; + for (it=Programmer::lister().begin(); it!=Programmer::lister().end(); ++it) + appendItem(it.key(), it.data()->label()); +} + +void ProgrammerStatusWidget::activatedSlot(int id) +{ + emit selected(*Programmer::lister().group(key(id))); +} + +//---------------------------------------------------------------------------- +ToolStatusWidget::ToolStatusWidget(QWidget *parent) + : QObject(parent), KeyPopupButton<QString>(parent) +{ + connect(widget(), SIGNAL(activated(int)), SLOT(activatedSlot(int))); + widget()->appendAction(i18n("Configure Toolchain..."), "configure", this, SIGNAL(configureToolchain())); + widget()->appendAction(i18n("Configure Compilation..."), "configure", this, SIGNAL(configure())); + widget()->appendSeparator(); + Tool::Lister::ConstIterator it; + for (it=Tool::lister().begin(); it!=Tool::lister().end(); ++it) + appendItem(it.key(), it.data()->label()); +} + +void ToolStatusWidget::activatedSlot(int id) +{ + emit selected(*Tool::lister().group(key(id))); +} + +//---------------------------------------------------------------------------- +ViewMenuAction::ViewMenuAction(KDockWidget *widget) + : KToggleAction(widget->tabPageLabel()), _widget(widget) +{} + +void ViewMenuAction::slotActivated() +{ + KAction::slotActivated(); + emit activated(_widget); +} + +//---------------------------------------------------------------------------- +MenuBarButton::MenuBarButton(const QString &icon, QWidget *parent) + : QToolButton(parent, "menu_bar_button") +{ + QFontMetrics fm(font()); + int h = fm.height() + 2*style().pixelMetric(QStyle::PM_DefaultFrameWidth, this); + setFixedHeight(h); + KIconLoader loader; + setIconSet(loader.loadIconSet(icon, KIcon::Small, fm.height()-2)); + setUsesTextLabel(false); + setAutoRaise(true); +} + +QSize MenuBarButton::sizeHint() const +{ + return QSize(QToolButton::sizeHint().width(), height()); +} diff --git a/src/libgui/toplevel_ui.h b/src/libgui/toplevel_ui.h new file mode 100644 index 0000000..8a5f631 --- /dev/null +++ b/src/libgui/toplevel_ui.h @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef TOPLEVEL_UI_H +#define TOPLEVEL_UI_H + +#include <qtoolbutton.h> +#include <kdockwidget.h> +#include <kaction.h> + +#include "common/gui/key_gui.h" +namespace Programmer { class Group; } +namespace Tool { class Group; } + +//---------------------------------------------------------------------------- +class ProgrammerStatusWidget : public QObject, public KeyPopupButton<QString> +{ +Q_OBJECT +public: + ProgrammerStatusWidget(QWidget *parent); + +signals: + void configure(); + void selected(const Programmer::Group &group); + +private slots: + void activatedSlot(int id); +}; + +//---------------------------------------------------------------------------- +class ToolStatusWidget : public QObject, public KeyPopupButton<QString> +{ +Q_OBJECT +public: + ToolStatusWidget(QWidget *parent); + +signals: + void configureToolchain(); + void configure(); + void selected(const Tool::Group &group); + +private slots: + void activatedSlot(int id); +}; + +//---------------------------------------------------------------------------- +class ViewMenuAction : public KToggleAction +{ +Q_OBJECT +public: + ViewMenuAction(KDockWidget *widget); + +signals: + void activated(QWidget *); + +private slots: + virtual void slotActivated(); + +private: + KDockWidget *_widget; +}; + +//---------------------------------------------------------------------------- +class MenuBarButton : public QToolButton +{ +Q_OBJECT +public: + MenuBarButton(const QString &icon, QWidget *parent); + virtual QSize sizeHint() const; +}; + +#endif diff --git a/src/libgui/watch_view.cpp b/src/libgui/watch_view.cpp new file mode 100644 index 0000000..984dc7c --- /dev/null +++ b/src/libgui/watch_view.cpp @@ -0,0 +1,225 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "watch_view.h" + +#include <qheader.h> +#include <qcombobox.h> +#include <kiconloader.h> + +#include "main_global.h" +#include "register_view.h" +#include "devices/base/device_group.h" +#include "devices/gui/device_group_ui.h" +#include "gui_debug_manager.h" +#include "editor_manager.h" +#include "common/gui/list_container.h" + +//----------------------------------------------------------------------------- +Register::BaseListView::BaseListView(QWidget *parent) + : ListView(parent), _root(0) +{ + header()->hide(); + setSorting(-1); + setFullWidth(true); + setRootIsDecorated(false); + setAllColumnsShowFocus(true); + connect(this, SIGNAL(mouseButtonClicked(int, QListViewItem *, const QPoint &, int)), + SLOT(itemClicked(int, QListViewItem *, const QPoint &, int))); + connect(this, SIGNAL(contextMenuRequested(QListViewItem *, const QPoint &, int)), + SLOT(contextMenu(QListViewItem *, const QPoint &, int))); +} + +//----------------------------------------------------------------------------- +Register::RegisterListView::RegisterListView(QWidget *parent) + : BaseListView(parent) +{ + addColumn(QString::null); +} + +void Register::RegisterListView::init(const Device::Data *data) +{ + delete _root; + _root = new ListViewItemContainer(i18n("Registers"), this); + KIconLoader loader; + _root->setPixmap(0, loader.loadIcon("piklab_chip", KIcon::Small)); + _root->setSelectable(false); + _root->setOpen(true); + if (data) Device::groupui(*data).fillWatchListContainer(_root, _ids); +} + +void Register::RegisterListView::updateView() +{ + QListViewItemIterator it(_root); + for (; it.current(); ++it) { + int id = _root->id(it.current()); + if ( id==-1 || _ids[id].type()==Invalid ) continue; + bool watched = Register::list().isWatched(_ids[id]); + static_cast<QCheckListItem *>(it.current())->setOn(watched); + } +} + +void Register::RegisterListView::itemClicked(int button, QListViewItem *item, const QPoint &, int) +{ + if ( item==0 || button!=LeftButton ) return; + if ( item==firstChild() ) Main::editorManager().openEditor(EditorManager::RegisterEditor); + int id = _root->id(item); + if ( id==-1 || _ids[id].type()==Invalid ) return; + bool watched = Register::list().isWatched(_ids[id]); + static_cast<QCheckListItem *>(item)->setOn(!watched); + Debugger::manager->setRegisterWatched(_ids[id], !watched); +} + +//----------------------------------------------------------------------------- +Register::WatchedListView::WatchedListView(QWidget *parent) + : BaseListView(parent), _popup(0), _base(NumberBase::Hex) +{ + setSorting(0); + addColumn(QString::null); + addColumn(QString::null); + addColumn(QString::null); + + _root = new ListViewItemContainer(i18n("Watched"), this); + KIconLoader loader; + _root->setPixmap(0, loader.loadIcon("viewmag", KIcon::Small)); + _root->setSelectable(false); + _root->setOpen(true); +} + +KPopupMenu *Register::WatchedListView::appendFormatMenu(KPopupMenu *parent, uint offset) +{ + KIconLoader loader; + QPixmap icon = loader.loadIcon("fonts", KIcon::Small); + KPopupMenu *popup = new KPopupMenu; + popup->insertTitle(i18n("Format")); + FOR_EACH(NumberBase, base) popup->insertItem(base.label(), offset + base.type()); + parent->insertItem(icon, i18n("Format"), popup); + return popup; +} + +void Register::WatchedListView::init(const Device::Data *data) +{ + delete _popup; + _popup = 0; + if ( data==0 ) return; + _popup = new PopupContainer(i18n("Watch Register"), this); + Device::groupui(*data).fillWatchListContainer(_popup, _ids); + _popup->insertSeparator(); + _formatPopup = appendFormatMenu(_popup, _ids.count()); + KIconLoader loader; + QPixmap icon = loader.loadIcon("cancel", KIcon::Small); + _popup->insertItem(icon, i18n("Clear"), Debugger::manager, SLOT(stopWatchAll())); +} + +void Register::WatchedListView::updateView() +{ + // delete items not watched anymore + for (QListViewItem *item=_root->firstChild(); item;) { + ListViewItem *ritem = static_cast<ListViewItem *>(item); + item = item->nextSibling(); + if ( !Register::list().isWatched(ritem->data()) ) delete ritem; + } + // add new items + bool added = false; + QValueList<Register::TypeData> watched = Register::list().watched(); + QValueVector<ListViewItem *> items(watched.count()); + for (uint k=0; k<watched.count(); k++) { + QListViewItem *item = _root->firstChild(); + for (; item; item=item->nextSibling()) + if ( static_cast<ListViewItem *>(item)->data()==watched[k] ) break; + if (item) { + items[k] = static_cast<ListViewItem *>(item); + items[k]->updateView(); + } else { + items[k] = Device::groupui(*Main::deviceData()).createWatchItem(watched[k], _root); + items[k]->setBase(_base); + added = true; + } + } +} + +QString Register::WatchedListView::tooltip(const QListViewItem &item, int col) const +{ + if ( item.rtti()==Register::PortBitRtti ) return static_cast<const PortBitListViewItem &>(item).tooltip(col); + if ( item.rtti()==Register::RegisterRtti ) return static_cast<const ListViewItem &>(item).tooltip(col); + return QString::null; +} + +void Register::WatchedListView::itemClicked(int button, QListViewItem *item, const QPoint &, int col) +{ + if ( item==0 || button!=LeftButton ) return; + else if ( item->rtti()==RegisterRtti ) { + if ( col==2 && Main::programmerState()==Programmer::Halted ) static_cast<ListViewItem *>(item)->startRename(); + else item->setOpen(!item->isOpen()); + } +} + +void Register::WatchedListView::contextMenu(QListViewItem *item, const QPoint &p, int) +{ + if ( item==0 ) return; + if ( item==firstChild() ) { + if ( _popup==0 ) return; + FOR_EACH(NumberBase, base) _formatPopup->setItemChecked(_ids.count()+base.type(), _base==base); + int res = _popup->exec(p); + if ( res<0 ) return; + if ( res<int(_ids.count()) ) Debugger::manager->setRegisterWatched(_ids[res], true); + else { + _base = NumberBase::Type(res-_ids.count()); + for (QListViewItem *item=_root->firstChild(); item; item=item->nextSibling()) + static_cast<ListViewItem *>(item)->setBase(_base); + } + } else { + if ( item->rtti()==Register::PortBitRtti ) return; + Register::ListViewItem *ritem = static_cast<ListViewItem *>(item); + KPopupMenu *pop = new KPopupMenu; + pop->insertTitle(ritem->label()); + QPopupMenu *fpop = appendFormatMenu(pop, 0); + FOR_EACH(NumberBase, base) fpop->setItemChecked(base.type(), ritem->base()==base); + pop->insertSeparator(); + KIconLoader loader; + QPixmap icon = loader.loadIcon("edit", KIcon::Small); + int editId = pop->insertItem(icon, i18n("Edit")); + pop->setItemEnabled(editId, Main::programmerState()==Programmer::Halted); + icon = loader.loadIcon("cancel", KIcon::Small); + int removeId = pop->insertItem(icon, i18n("Remove")); + int res = pop->exec(p); + if ( res==editId ) ritem->startRename(); + else if ( res==removeId ) Debugger::manager->setRegisterWatched(ritem->data(), false); + else if ( res>=0 ) ritem->setBase(NumberBase::Type(res)); + delete pop; + } +} + +//----------------------------------------------------------------------------- +Register::WatchView::WatchView(QWidget *parent) + : QWidget(parent, "watch_view"), GenericView(Register::list()), _data(0) +{ + QVBoxLayout *top = new QVBoxLayout(this); + QValueList<int> sizes; + sizes.append(50); + Splitter *splitter = new Splitter(sizes, Qt::Vertical, this, "watch_window_splitter"); + top->addWidget(splitter); + + _registerListView = new RegisterListView(splitter); + _watchedListView = new WatchedListView(splitter); +} + +void Register::WatchView::init(bool force) +{ + if ( !force && _data==Main::deviceData() ) return; + _data = Main::deviceData(); + _registerListView->init(_data); + _watchedListView->init(_data); + updateView(); +} + +void Register::WatchView::updateView() +{ + _registerListView->updateView(); + _watchedListView->updateView(); +} diff --git a/src/libgui/watch_view.h b/src/libgui/watch_view.h new file mode 100644 index 0000000..a7ac24c --- /dev/null +++ b/src/libgui/watch_view.h @@ -0,0 +1,94 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#ifndef WATCH_VIEW_H +#define WATCH_VIEW_H + +#include "common/gui/list_container.h" +#include "common/common/storage.h" +#include "common/gui/list_view.h" +#include "devices/base/register.h" +namespace Device { class Data; } + +namespace Register +{ + +//----------------------------------------------------------------------------- +class BaseListView : public ListView +{ +Q_OBJECT +public: + BaseListView(QWidget *parent); + virtual void init(const Device::Data *data) = 0; + virtual void updateView() = 0; + +private slots: + virtual void itemClicked(int button, QListViewItem *item, const QPoint &p, int col) = 0; + virtual void contextMenu(QListViewItem *item, const QPoint &p, int col) = 0; + +protected: + ListViewItemContainer *_root; + QValueVector<Register::TypeData> _ids; +}; + +//----------------------------------------------------------------------------- +class RegisterListView : public BaseListView +{ +Q_OBJECT +public: + RegisterListView(QWidget *parent); + virtual void init(const Device::Data *data); + virtual void updateView(); + +private slots: + virtual void itemClicked(int button, QListViewItem *item, const QPoint &p, int col); + virtual void contextMenu(QListViewItem *, const QPoint &, int) {} +}; + +//----------------------------------------------------------------------------- +class WatchedListView : public BaseListView +{ +Q_OBJECT +public: + WatchedListView(QWidget *parent); + virtual QString tooltip(const QListViewItem &item, int col) const; + virtual void init(const Device::Data *data); + virtual void updateView(); + +private slots: + virtual void itemClicked(int button, QListViewItem *item, const QPoint &p, int col); + virtual void contextMenu(QListViewItem *item, const QPoint &p, int col); + +private: + PopupContainer *_popup; + KPopupMenu *_formatPopup; + NumberBase _base; + + static KPopupMenu *appendFormatMenu(KPopupMenu *parent, uint offset); +}; + +//----------------------------------------------------------------------------- +class WatchView : public QWidget, public GenericView +{ +Q_OBJECT +public: + WatchView(QWidget *parent); + void init(bool force); + +public slots: + virtual void updateView(); + +private: + WatchedListView *_watchedListView; + RegisterListView *_registerListView; + const Device::Data *_data; +}; + +} // namespace + +#endif |