/** * DebuggerWidgets.h * Copyright (c) 2013 ROBLOX Corp. All Rights Reserved. */ #pragma once //this will make sure that we can use qt with boost (else moc compiler errors) #ifndef QT_NO_KEYWORDS #define QT_NO_KEYWORDS #endif // standard C/C++ Headers #include // 3rd Party Headers #include "boost/shared_ptr.hpp" // Roblox Headers #include "script/DebuggerManager.h" // Qt Headers #include #include #include #include // Roblox Studio Headers namespace RBX { namespace Reflection { class PropertyDescriptor; } } class QDockWidget; class QToolButton; class BreakpointsWidget; class CallStackWidget; class DebuggerClient; class DebuggerViewsManager { public: static DebuggerViewsManager& Instance(); enum EDebuggerViewID { eDV_BREAKPOINTS, eDV_CALLSTACK, eDV_WATCH, eDV_MAX }; template T& getViewWidget(EDebuggerViewID id) const { RBXASSERT(m_ViewWidgets.contains(id)); RBXASSERT(m_ViewWidgets[id]); QWidget* widget = m_ViewWidgets[id]; RBXASSERT(dynamic_cast(widget)); return static_cast(*widget); } void showDockWidget(EDebuggerViewID dockId); private: DebuggerViewsManager(); void restoreViews(); void saveViews(); void onDebuggingStarted(); void onDebuggingStopped(); void onDebuggerClientActivated(int currentBreakpoint, RBX::Scripting::ScriptDebugger::Stack currentStack); void onDebuggerClientDeactivated(); void onExecutionDataCleared(); void onBreakpointEncountered(int currentBreakpoint, DebuggerClient* pDebuggerClient); void onClearAll(); void onBreakpointAdded(shared_ptr spBreakpoint); void onBreakpointRemoved(shared_ptr spBreakpoint); void onWatchAdded(shared_ptr spWatch); void onWatchRemoved(shared_ptr spWatch); void onDebuggersListUpdated(DebuggerClient* pDebuggerClient); QMap m_DockWidgets; QMap m_ViewWidgets; std::list m_cConnections; bool m_bBreakpointEncountered; }; class DebuggerTreeWidgetItem : public QTreeWidgetItem { public: DebuggerTreeWidgetItem() {} //no-op functions virtual void activate() {} virtual void columnModified(int column) {} }; class DebuggerTreeWidget : public QTreeWidget { Q_OBJECT public: DebuggerTreeWidget(QWidget* pParent); Q_SIGNALS: void deleteSelectedItem(); protected Q_SLOTS: virtual void onItemActivated(QTreeWidgetItem*); virtual void onItemChanged(QTreeWidgetItem*, int); protected: virtual void mousePressEvent(QMouseEvent *evt); virtual void keyPressEvent(QKeyEvent * evt); }; class StackDetailsItem : public DebuggerTreeWidgetItem { public: StackDetailsItem(const RBX::Scripting::ScriptDebugger::FunctionInfo& funcInfo, bool isFirstItem); ~StackDetailsItem(); void activate(); void updateIcon(bool isCurrent); private: int getLine(); int getFrame(); boost::shared_ptr m_spAssociatedScript; bool m_bIsFirstItem; }; class CallStackTreeWidget : public DebuggerTreeWidget { Q_OBJECT public: CallStackTreeWidget(QWidget* pParent=0); ~CallStackTreeWidget(); void setCallStack(const RBX::Scripting::ScriptDebugger::Stack& stack); private: void onItemActivated(QTreeWidgetItem* pItem); QTreeWidgetItem* m_pPreviousItem; }; class CallStackDebuggersList: public QComboBox { Q_OBJECT public: CallStackDebuggersList(QWidget* pWidget); /*override*/ void showPopup(); bool isDirty() { return m_bIsDirty;} void setDirty(bool state) { m_bIsDirty = state;} Q_SIGNALS: void popupAboutToShow(); private: bool m_bIsDirty; }; class CallStackWidget : public QWidget { Q_OBJECT public: CallStackWidget(QWidget* pParent=0); void populateDebuggers(DebuggerClient* pDebuggerClient); void clearDebuggers(); void setCallStack(const RBX::Scripting::ScriptDebugger::Stack& stack); void clear(); private Q_SLOTS: void onCurrentIndexChanged(int index); void onDebuggerListPopupShow(); private: CallStackTreeWidget *m_pCallStackTreeWidget; QComboBox *m_pScriptDebuggersList; DebuggerClient *m_pCurrentDebuggerClient; }; class BreakpointItem : public DebuggerTreeWidgetItem { public: BreakpointItem(boost::shared_ptr breakpoint); ~BreakpointItem(); bool hasBreakpoint(boost::shared_ptr breakpoint); void columnModified(int column); void activate(); void setBreakpointEnabled(bool state); bool isBreakpointEnabled(); void deleteBreakpoint(); private: void onBreakpointPropertyChanged(const RBX::Reflection::PropertyDescriptor* pPropertyDescriptor); void onScriptAncestryChanged(shared_ptr newParent); boost::shared_ptr m_spBreakpoint; rbx::signals::scoped_connection m_cPropertyChangedConnection; rbx::signals::scoped_connection m_cAncestoryChangedConnection; bool m_bIgnoreBreakpointModification; bool m_bIgnoreWaypointRequest; }; class BreakpointsTreeWidget : public DebuggerTreeWidget { public: BreakpointsTreeWidget(QWidget* pParent=0); void addBreakpoint(boost::shared_ptr breakpoint); void removeBreakpoint(boost::shared_ptr breakpoint); void setCurrentBreakpoint(int breakpointLine); void deleteSelectedBreakpoint(); void deleteAllBreakpoints(); void disableEnableAllBreakpoints(); void goToSourceCode(); bool hasBreakpointsEnabled(); private: BreakpointItem* findBreakpointItem(boost::shared_ptr breakpoint); BreakpointItem* findBreakpointItem(int breakpointLine); }; class BreakpointsWidget: public QWidget { Q_OBJECT public: BreakpointsWidget(QWidget* pParent=0); //delegate functions void addBreakpoint(boost::shared_ptr breakpoint); void removeBreakpoint(boost::shared_ptr breakpoint); void setCurrentBreakpoint(int breakpointLine); void clear(); int numBreakpoints() { return m_pBreakpointTreeWidget ? m_pBreakpointTreeWidget->topLevelItemCount() : 0; } private Q_SLOTS: void onPushButtonClicked(); void onDeleteSelectedItem(); void requestButtonsStatusUpdate(); void updateButtonsStatus(); private: BreakpointsTreeWidget* m_pBreakpointTreeWidget; QToolButton* m_pDeleteBreakpointTB; QToolButton* m_pDeleteAllBreakpointsTB; QToolButton* m_pDisableEnableAllBreakpointsTB; QToolButton* m_pGoToSourceCodeTB; bool m_bPushButtonStateUpdateRequested; bool m_bIgnoreBreakpointModification; }; class WatchItem : public DebuggerTreeWidgetItem { public: WatchItem(boost::shared_ptr spWatch); ~WatchItem(); void updateWatchValue(); bool hasWatch(boost::shared_ptr spWatch); void columnModified(int column); void deleteWatch(); virtual void setInvalid(bool state); bool isInvalid() { return m_bIsInValid; } private: void onWatchPropertyChanged(const RBX::Reflection::PropertyDescriptor* pPropertyDescriptor); void onScriptAncestryChanged(shared_ptr newParent); void removeChildren(); boost::shared_ptr m_spWatch; rbx::signals::scoped_connection m_cPropertyChangedConnection; rbx::signals::scoped_connection m_cAncestoryChangedConnection; bool m_bIgnoreWatchModification; bool m_bIsInValid; }; class WatchTreeWidget : public DebuggerTreeWidget { Q_OBJECT public: WatchTreeWidget(QWidget *pParent); void addWatch(boost::shared_ptr spWatch); void removeWatch(boost::shared_ptr spWatch); void deleteSelectedWatch(); QTreeWidgetItem* itemFromIndex(QModelIndex index) const { return QTreeWidget::itemFromIndex(index); } void clear(); public Q_SLOTS: void updateWatchValues(bool enable); private Q_SLOTS: void copySelectedItem(); void addWatch(); void removeWatch(); void deleteAllWatches(); private: virtual void contextMenuEvent(QContextMenuEvent* evt); virtual void mousePressEvent(QMouseEvent *event); WatchItem* findWatchItem(boost::shared_ptr spWatch); QString getFullName(QTreeWidgetItem *pItem); void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void addDummyWatchItem(); QMenu* m_pContextualMenu; QAction* m_pCopyAction; QAction* m_pAddWatchAction; QAction* m_pDeleteWatchAction; QAction* m_pDeleteAllWatchesAction; bool m_bIgnoreWatchModification; }; class WatchWidget : public QWidget { Q_OBJECT public: WatchWidget(QWidget *pParent=0); void addWatch(shared_ptr spWatch); void removeWatch(shared_ptr spWatch); void updateWatchValues(bool enable = false); void clear(); private Q_SLOTS: void onDeleteSelectedItem(); private: WatchTreeWidget* m_pWatchTreeWidget; }; class DebuggerToolTipWidget: public QTreeWidget { Q_OBJECT public: DebuggerToolTipWidget(QWidget *pParent); void showToolTip(const QPoint& pos, const QString &key, const RBX::Reflection::Variant &value); void hideToolTip(); bool isKeyValid(const QString& key) { return key == m_Key; } void showAt(const QPoint& pos); private Q_SLOTS: void computeToolTipSize(); void onTimeout(); private: void mousePressEvent(QMouseEvent * evt); void mouseMoveEvent(QMouseEvent * evt); bool eventFilter(QObject *obj, QEvent *evt); void wheelEvent(QWheelEvent * e); int getDepth(QTreeWidgetItem *pItem); int computeToolTipHeight(const QModelIndex &index); QTimer* m_pExpansionTimer; QTreeWidgetItem* m_pModifiedByMouse; QString m_Key; RBX::Reflection::Variant m_Value; };