diff --git a/CbersApp.pro b/CbersApp.pro new file mode 100644 index 0000000..3863783 --- /dev/null +++ b/CbersApp.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs +SUBDIRS = CbersUI x3py CbersPluginCore CbersApp plugins +CbersApp.depends = CbersUI CbersPluginCore plugins +CbersPluginCore.depends = x3py +plugins.depends = CbersPluginCore diff --git a/CbersApp/CbersApp.ico b/CbersApp/CbersApp.ico new file mode 100644 index 0000000..c693aaf Binary files /dev/null and b/CbersApp/CbersApp.ico differ diff --git a/CbersApp/CbersApp.pro b/CbersApp/CbersApp.pro new file mode 100644 index 0000000..287af34 --- /dev/null +++ b/CbersApp/CbersApp.pro @@ -0,0 +1,116 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2016-09-08T16:10:14 +# +#------------------------------------------------- + +QT += core gui opengl xml + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +TARGET = CbersApp +TEMPLATE = app + +{ + CONFIG(debug, debug|release){ + TARGET = $$join(TARGET,,,d) + + DESTDIR = $$PWD/../bin/debug + } + else{ + DESTDIR = $$PWD/../bin/release + } +} + + +SOURCES += main.cpp\ + mainwindow.cpp \ + pluginmanager.cpp \ + ribbonpluginmanager.cpp + +HEADERS += mainwindow.h \ + pluginmanager.h \ + ribbonpluginmanager.h + +FORMS += mainwindow.ui + + +CONFIG(release, debug|release): LIBS += -L$$PWD/../lib/release/ -lCbersUI +else:CONFIG(debug, debug|release): LIBS += -L$$PWD/../lib/debug/ -lCbersUId + +unix{ + LIBS += -ldl +} + +INCLUDEPATH += $$PWD/../include +INCLUDEPATH += $$PWD/../include/CbersUI +INCLUDEPATH += $$PWD/../include/x3py +INCLUDEPATH += $$PWD/../include/PluginCore +DEPENDPATH += $$PWD/../include +DEPENDPATH += $$PWD/../include/CbersUI +DEPENDPATH += $$PWD/../include/x3py +DEPENDPATH += $$PWD/../include/PluginCore + +win32{ + LIBS += -lDbghelp +} + +SDK_PATH = $$PWD/../ + +win32{ + RC_FILE= CbersApp_win32.rc +} + +RESOURCES += \ + CbersApp.qrc + +TRANSLATION_DIR = $$PWD/../i18n/ +TRANSLATIONS = $$TRANSLATION_DIR/CbersApp_zh_CN.ts + +# Copies the given files to the destination directory +defineReplace(copyToDir) { + files = $$1 + DIR = $$2 + SRCDIR = $$3 + LINK = + + win32:DIR ~= s,/,\\,g + win32{ + LINK += if not exist $$quote($$DIR) ( $$QMAKE_MKDIR $$quote($$DIR) ) $$escape_expand(\\n\\t) + } + unix{ + LINK += $$QMAKE_MKDIR $$quote($$DIR) $$escape_expand(\\n\\t) + } + for(FILE, files) { + !isEmpty(SRCDIR){ + FILE = $$SRCDIR/$$FILE + } + win32:FILE ~= s,/,\\,g + LINK += $$QMAKE_COPY $$quote($$FILE) $$quote($$DIR) $$escape_expand(\\n\\t) + } + return($$LINK) +} + +win32{ + QMAKE_POST_LINK += cd $$quote($$PWD) $$escape_expand(\\n\\t) +} +unix{ + QMAKE_POST_LINK += cd $$quote($$PWD) $$escape_expand(\\n\\t) +} + +# Auto Update And Release TRANSLATIONS +win32:TRANSLATION_DIR ~= s,/,\\,g +win32{ + QMAKE_POST_LINK += if not exist $$quote($$TRANSLATION_DIR) ( $$QMAKE_MKDIR $$quote($$TRANSLATION_DIR) ) $$escape_expand(\\n\\t) +} +unix{ + QMAKE_POST_LINK += $$QMAKE_MKDIR -p $$quote($$TRANSLATION_DIR) $$escape_expand(\\n\\t) +} + +QMAKE_POST_LINK += $(QTDIR)/bin/lupdate $$PWD/CbersApp.pro $$escape_expand(\\n\\t) +QMAKE_POST_LINK += $(QTDIR)/bin/lrelease $$PWD/CbersApp.pro $$escape_expand(\\n\\t) +RELEASE_TRANSLATIONS = $$TRANSLATIONS +RELEASE_TRANSLATIONS ~= s,.ts,.qm,g +QMAKE_POST_LINK += $$copyToDir($$RELEASE_TRANSLATIONS, $$DESTDIR/i18n/) diff --git a/CbersApp/CbersApp.qrc b/CbersApp/CbersApp.qrc new file mode 100644 index 0000000..15ac2ad --- /dev/null +++ b/CbersApp/CbersApp.qrc @@ -0,0 +1,5 @@ + + + CbersApp.ico + + diff --git a/CbersApp/CbersApp_win32.rc b/CbersApp/CbersApp_win32.rc new file mode 100644 index 0000000..8338870 --- /dev/null +++ b/CbersApp/CbersApp_win32.rc @@ -0,0 +1,36 @@ +#include "winver.h" + +IDI_ICON1 ICON "CbersApp.ico" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x0L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080404b0" + BEGIN + VALUE "CompanyName", "CbersApp" + VALUE "FileDescription", "CbersApp" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "CbersApp.exe" + VALUE "LegalCopyright", "Copyright (C) 2018" + VALUE "OriginalFilename", "CbersApp.exe" + VALUE "ProductName", "CbersApp" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x804, 1200 + END +END \ No newline at end of file diff --git a/CbersApp/main.cpp b/CbersApp/main.cpp new file mode 100644 index 0000000..ca83ca4 --- /dev/null +++ b/CbersApp/main.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include +#include +#include "mainwindow.h" +#include "pluginmanager.h" +#include "x3py/observer/observerimpl.h" + +int main(int argc, char *argv[]) +{ + QString configpath = QFileInfo(QString::fromLocal8Bit(argv[0])).absolutePath() + "/config"; + QSettings::setDefaultFormat( QSettings::IniFormat ); + QSettings::setPath( QSettings::IniFormat, QSettings::UserScope, configpath); + + QApplication a(argc, argv); + a.setWindowIcon(QIcon(":/CbersApp.ico")); + + QCoreApplication::setOrganizationName( QObject::tr("CbersApp") ); + QCoreApplication::setOrganizationDomain( QObject::tr("CbersApp") ); + QCoreApplication::setApplicationName( QObject::tr("CbersApp") ); + QCoreApplication::setAttribute( Qt::AA_DontShowIconsInMenus, false ); + + QSettings mySettings; + ////////////////////////////////////////////////////////////// + // Load Translator + QString i18nPath = QApplication::applicationDirPath() + "/i18n"; + QString myUserLocale = mySettings.value( "locale/userLocale", "" ).toString(); + bool myLocaleOverrideFlag = mySettings.value( "locale/overrideFlag", false ).toBool(); + QString myTranslationCode; + if ( !myTranslationCode.isNull() && !myTranslationCode.isEmpty() ) + { + mySettings.setValue( "locale/userLocale", myTranslationCode ); + } + else + { + if ( !myLocaleOverrideFlag || myUserLocale.isEmpty() ) + { + myTranslationCode = QLocale::system().name(); + mySettings.setValue( "locale/userLocale", myTranslationCode ); + } + else + { + myTranslationCode = myUserLocale; + } + } + + QTranslator apptor( 0 ); + QTranslator cbersUItor( 0 ); + QTranslator qttor( 0 ); + if ( myTranslationCode != "C" ) + { + if ( apptor.load( QString( "CbersApp_" ) + myTranslationCode, i18nPath ) ) + { + a.installTranslator( &apptor ); + } + else + { + qWarning( "loading of CbersApp translation failed [%s]", QString( "%1/CbersApp_%2" ).arg( i18nPath ).arg( myTranslationCode ).toLocal8Bit().constData() ); + } + + if ( cbersUItor.load( QString( "CbersUI_" ) + myTranslationCode, i18nPath ) ) + { + a.installTranslator( &cbersUItor ); + } + else + { + qWarning( "loading of CbersUI translation failed [%s]", QString( "%1/CbersUI_%2" ).arg( i18nPath ).arg( myTranslationCode ).toLocal8Bit().constData() ); + } + + if ( qttor.load( QString( "qt_" ) + myTranslationCode, i18nPath ) ) + { + a.installTranslator( &qttor ); + } + else + { + qWarning( "loading of qt translation failed [%s]", QString( "%1_%2" ).arg( i18nPath ).arg( myTranslationCode ).toLocal8Bit().constData() ); + } + } + ////////////////////////////////////////////////////////////// + + if( !CPluginManager::Initialize("CbersPlugins") ) + return -1; + + MainWindow w; + w.showMaximized(); + + return a.exec(); +} diff --git a/CbersApp/mainwindow.cpp b/CbersApp/mainwindow.cpp new file mode 100644 index 0000000..212059b --- /dev/null +++ b/CbersApp/mainwindow.cpp @@ -0,0 +1,67 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include +#include +#include "ribbonpluginmanager.h" +#include "qribbonstylesheetmanager.h" + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + setObjectName("QRibbonMainWindow"); + setWindowFlags( Qt::FramelessWindowHint ); + ui->setupUi(this); + + mRibbonBar = new QRibbonBar(this->centralWidget()); + + mMdiArea = new QMdiArea(this->centralWidget()); + //mMdiArea->setOption(QMdiArea::DontMaximizeSubWindowOnActivation); + mMdiArea->setViewMode(QMdiArea::SubWindowView); + //mMdiArea->setViewMode(QMdiArea::TabbedView); + mMdiArea->setTabShape(QTabWidget::Rounded); + mMdiArea->setTabPosition(QTabWidget::North); + connect(mMdiArea, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(subWindowActivated(QMdiSubWindow *))); + + CRibbonPluginManager::getInstance()->Create(this, mRibbonBar, mMdiArea); + setMenuWidget(mRibbonBar); + setCentralWidget(mMdiArea); + + QRibbonStyleSheetManager::instance()->applyStyleSheet("office2007_black"); + //registerHandlers(); +} + +MainWindow::~MainWindow() +{ + CRibbonPluginManager::getInstance()->DestroyControl(); + + if( mRibbonBar!=nullptr ) + delete mRibbonBar; + mRibbonBar = nullptr; + + delete ui; +} + +bool MainWindow::OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam) +{ + //if( _stricmp(eventKey.c_str(), "scaleChanged")==0 ) + //{ + //} + return true; +} + +void MainWindow::subWindowActivated(QMdiSubWindow* pSubWindow) +{ + if( pSubWindow==Q_NULLPTR ) + return; + + QVariant vtData = pSubWindow->property("IUIPlugin"); + if( !vtData.isValid() ) + return; + + x3::Object spCommon((IUIPlugin*)(vtData.toLongLong())); + if( !spCommon.valid() ) + return; + + CRibbonPluginManager::getInstance()->SetViewer(spCommon.p()); +} diff --git a/CbersApp/mainwindow.h b/CbersApp/mainwindow.h new file mode 100644 index 0000000..c699665 --- /dev/null +++ b/CbersApp/mainwindow.h @@ -0,0 +1,44 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qribbonbar.h" +USING_NAMESPACE_CBERSUI + +#include "UIPluginsEvents.h" +USING_NAMESPACE_CBERSPLUGINS + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow, public IAnythingEventObserver +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +public: + // IAnythingEventObserver + virtual bool OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam); + +protected slots: + void subWindowActivated(QMdiSubWindow *); + +private: + Ui::MainWindow *ui; + QRibbonBar* mRibbonBar; + QMdiArea* mMdiArea; +}; + +#endif // MAINWINDOW_H diff --git a/CbersApp/mainwindow.ui b/CbersApp/mainwindow.ui new file mode 100644 index 0000000..3d7e2b4 --- /dev/null +++ b/CbersApp/mainwindow.ui @@ -0,0 +1,22 @@ + + + MainWindow + + + + 0 + 0 + 400 + 300 + + + + MainWindow + + + + + + + + diff --git a/CbersApp/pluginmanager.cpp b/CbersApp/pluginmanager.cpp new file mode 100644 index 0000000..5ea1f08 --- /dev/null +++ b/CbersApp/pluginmanager.cpp @@ -0,0 +1,269 @@ +#include "pluginmanager.h" +#include "x3py/nonplugin/scanplugins.h" +#include "x3py/manager/x3manager.h" +#include "x3py/manager/iplugins.h" + +int CPluginManager::MINID = 3000; +int CPluginManager::MAXID = 3999; + +CPluginManager::CPluginManager(void) +{ + m_nNextID = MINID; + m_nLastTool = -1; +} + +CPluginManager::~CPluginManager(void) +{ + UnloadPlugins(); +} + +bool CPluginManager::Initialize(const char* folder) +{ + return x3::loadScanPlugins(folder)>0; +} + +bool CPluginManager::UnInitialize() +{ + x3::unloadScanPlugins(); + return true; +} + +bool CPluginManager::LoadPlugins() +{ + UnloadPlugins(); + + x3::Object spPlugins(x3::clsidManager); + if( !spPlugins.valid() || spPlugins->getPluginCount()<=0 ) + return false; + + x3::Object spUICore(clsidUICore); + x3::LockRW lockcls(m_mapPlugin.locker, true); + bool ret = false; + if( lockcls.canWrite() ) + { + int nCount = spPlugins->getCLSIDCount(); + for( int i=0; igetCLSID(i); + if( clsid==NULL ) + continue; + + x3::Object spCommon(clsid); + if( !spCommon.valid() ) + continue; + + if( !spCommon->Initialize() ) + continue; + + if( spUICore.valid() ) + spUICore->Add(spCommon->getClassName(), spCommon.p()); + + x3::Object spView = spCommon; + if( spView.valid() ) + m_mapView.push_back(spView.p()); + else + { + int nNextID = GetNextID(); + if( nNextID==-1 ) + break; + + m_mapPlugin[nNextID] = spCommon.p(); + } + ret = true; + } + } + + return ret; +} + +bool CPluginManager::UnloadPlugins() +{ + x3::Object spUICore(clsidUICore); + x3::LockRW lockcls(m_mapPlugin.locker, true); + if( lockcls.canWrite() ) + { + hash_map::iterator it = m_mapPlugin.begin(); + for( ; it!=m_mapPlugin.end(); it++ ) + { + if( it->second.valid() ) + { + x3::Object spCommond(it->second); + if( spCommond.valid() ) + { + if( spUICore.valid() ) + spUICore->Remove(spCommond->getClassName()); + spCommond->UnInitialize(); + } + } + } + m_mapPlugin.clear(); + m_nNextID = MINID; + m_nLastTool = -1; + + x3::LockRW lockcls2(m_mapIdleID.locker, true); + if( lockcls2.canWrite() ) + m_mapIdleID.clear(); + } + + { + x3::LockRW lockcls(m_mapView.locker, true); + if( lockcls.canWrite() ) + { + std::vector::iterator it = m_mapView.begin(); + for( ; it!=m_mapView.end(); it++ ) + { + if( (*it).valid() ) + { + x3::Object spCommond(*it); + if( spCommond.valid() ) + { + if( spUICore.valid() ) + spUICore->Remove(spCommond->getClassName()); + spCommond->UnInitialize(); + } + } + } + m_mapView.clear(); + } + } + + return true; +} + +int CPluginManager::GetNextID() +{ + x3::LockRW lockcls(m_mapIdleID.locker, true); + int ret = -1; + if( lockcls.canWrite() ) + { + std::vector::iterator it = m_mapIdleID.begin(); + if( it!=m_mapIdleID.end() ) + { + ret = *it; + m_mapIdleID.erase(it); + } + } + + if( ret!=-1 ) + return ret; + + if( m_nNextID>MAXID ) + return ret; + + ret = m_nNextID++; + return ret; +} + +void CPluginManager::FreeID(int id) +{ + if( id==m_nLastTool ) + m_nLastTool = -1; + + if( idMAXID || id>=m_nNextID ) + return; + + x3::LockRW lockcls(m_mapIdleID.locker, true); + if( lockcls.canWrite() ) + { + std::vector::iterator it = m_mapIdleID.begin(); + for( ; it!=m_mapIdleID.end(); it++ ) + { + if( *it==id ) + return; + } + + m_mapIdleID.push_back(id); + } +} + +int CPluginManager::GetViewPluginCount() +{ + x3::LockRW lockcls(m_mapView.locker); + int ret = 0; + if( lockcls.canRead() ) + ret = m_mapView.size(); + + return ret; +} + +bool CPluginManager::GetViewPlugin(int index, IUIView** ppIView) +{ + x3::LockRW lockcls(m_mapView.locker); + IUIView* ret = nullptr; + if( lockcls.canRead() ) + { + if( index>=0 && index::iterator it = m_mapView.begin() + index; + if( it!=m_mapView.end() ) + { + x3::Object spCommon(*it); + ret = spCommon.p(); + } + } + } + + return ret; +} + +int CPluginManager::GetPluginCount() +{ + x3::LockRW lockcls(m_mapPlugin.locker); + int ret = 0; + if( lockcls.canRead() ) + ret = m_mapPlugin.size(); + + return ret; +} + +IUIPlugin* CPluginManager::FindPlugin(int id) +{ + x3::LockRW lockcls(m_mapPlugin.locker); + IUIPlugin* ret = nullptr; + if( lockcls.canRead() ) + { + hash_map::iterator it = m_mapPlugin.find(id); + if( it!=m_mapPlugin.end() ) + { + x3::Object spCommon(it->second); + ret = spCommon.p(); + } + } + + return ret; +} + +bool CPluginManager::GetPlugin(int index, int& id, IUIPlugin** ppICommon) +{ + if( ppICommon==NULL ) + return false; + + x3::LockRW lockcls(m_mapPlugin.locker); + bool ret = false; + if( lockcls.canRead() ) + { + if( index>=0 && index::iterator it = m_mapPlugin.begin(); + for( int i=0; ifirst; + if( *ppICommon!=NULL ) + { + (*ppICommon)->releaseObject(); + *ppICommon = NULL; + } + + x3::Object spCommon(it->second); + *ppICommon = spCommon.p(); + if( *ppICommon!=NULL ) + ret = true; + } + } + } + + return ret; +} diff --git a/CbersApp/pluginmanager.h b/CbersApp/pluginmanager.h new file mode 100644 index 0000000..d162c5c --- /dev/null +++ b/CbersApp/pluginmanager.h @@ -0,0 +1,51 @@ +#ifndef CPLUGINMANAGER_H +#define CPLUGINMANAGER_H +#include "x3py/module/plugininc.h" +#include "x3py/objptr.h" +#include "x3py/utilfunc/lockrw.h" +#include "UIPlugins.h" +USING_NAMESPACE_CBERSPLUGINS + +#include +#include + +#define hash_multimap std::multimap +#define hash_map std::map + +class CPluginManager +{ +public: + CPluginManager(); + ~CPluginManager(void); + +public: + static bool Initialize(const char* folder = "plugins"); + static bool UnInitialize(); + +public: + bool LoadPlugins(); + bool UnloadPlugins(); + int GetPluginCount(); + bool GetPlugin(int index, int& id, IUIPlugin** ppICommon); + IUIPlugin* FindPlugin(int id); + + int GetViewPluginCount(); + bool GetViewPlugin(int index, IUIView** ppIView); + +protected: + int GetNextID(); + void FreeID(int id); + +public: + static int MINID; + static int MAXID; + +protected: + x3::LockRW_> m_mapPlugin; + x3::LockRW_> m_mapView; + x3::LockRW_> m_mapIdleID; + int m_nNextID; + int m_nLastTool; +}; + +#endif // CPLUGINMANAGER_H diff --git a/CbersApp/ribbonpluginmanager.cpp b/CbersApp/ribbonpluginmanager.cpp new file mode 100644 index 0000000..e286d54 --- /dev/null +++ b/CbersApp/ribbonpluginmanager.cpp @@ -0,0 +1,321 @@ +#include "ribbonpluginmanager.h" +#include "x3py/manager/iworkpath.h" +#include "x3py/manager/x3manager.h" +#include +#include +#include +#include +#include +#include + +CRibbonPluginManager* CRibbonPluginManager::s_pManager = nullptr; +CRibbonPluginManager::CRibbonPluginManager(void) +{ + m_spViewer = NULL; +} + +CRibbonPluginManager::~CRibbonPluginManager(void) +{ + DestroyControl(); +} + +CRibbonPluginManager* CRibbonPluginManager::getInstance() +{ + if( s_pManager==nullptr ) + s_pManager = new CRibbonPluginManager(); + return s_pManager; +} + +void CRibbonPluginManager::Destroy() +{ + if( s_pManager!=nullptr ) + delete s_pManager; + s_pManager = nullptr; +} + +bool CRibbonPluginManager::Create(QMainWindow* pFrameWnd, QRibbonBar* pRibbonBar, QMdiArea* pMdiArea) +{ + if( !LoadPlugins() ) + return false; + + if( !CreateViews(pFrameWnd, pMdiArea) ) + return false; + + return CreateControl(pRibbonBar, pFrameWnd); +} + +bool CRibbonPluginManager::CreateViews(QMainWindow* pFrameWnd, QMdiArea* pMdiArea) +{ + if( pMdiArea==nullptr ) + return false; + + x3::LockRW lockcls(m_mapView.locker); + bool ret = false; + if( lockcls.canRead() ) + { + m_spViewer = nullptr; + std::vector::iterator it = m_mapView.begin(); + for( ; it!=m_mapView.end(); it++ ) + { + x3::Object spCommon(*it); + if( !spCommon.valid() ) + continue; + + x3::Object spView(spCommon); + if( !spView.valid() ) + continue; + + spView->setMainWindow(pFrameWnd); + qDebug("CreateView: %s\n", (*it)->getClassName()); + QWidget* pWidget = spView->getViewWidget(); + if( pWidget==nullptr ) + continue; + + QMdiSubWindow* pSubWindow = pMdiArea->addSubWindow(pWidget); + pSubWindow->setAttribute(Qt::WA_DeleteOnClose); + pSubWindow->setProperty("IUIPlugin", QVariant((qlonglong)(spCommon.p()))); + //pSubWindow->setWindowFlags(Qt::FramelessWindowHint); + pSubWindow->showMaximized(); + pWidget->showMaximized(); + if( pSubWindow!=nullptr && pMdiArea->subWindowList().size()==1 ) + pMdiArea->setActiveSubWindow(pSubWindow); + if( !m_spViewer.valid() ) + m_spViewer = spView; + ret = true; + } + qDebug("CreateViews End\n"); + } + + return ret; +} + +bool CRibbonPluginManager::CreateControl(QRibbonBar* pRibbonBar, QMainWindow* pFrameWnd) +{ + if( pRibbonBar==nullptr || pFrameWnd==nullptr ) + return false; + + x3::LockRW lockcls(m_mapPlugin.locker); + bool ret = false; + if( lockcls.canRead() ) + { + QDockWidget* pFirstLeftDockWidget = Q_NULLPTR; + QDockWidget* pFirstRightDockWidget = Q_NULLPTR; + QDockWidget* pFirstTopDockWidget = Q_NULLPTR; + QDockWidget* pFirstBottomDockWidget = Q_NULLPTR; + hash_map::iterator it = m_mapPlugin.begin(); + for( ; it!=m_mapPlugin.end(); it++ ) + { + x3::Object spCommon(it->second); + if( !spCommon.valid() ) + continue; + + qDebug("CreateControl: %s\n", it->second->getClassName()); + if( m_spViewer.valid() ) + spCommon->SetBuddy(m_spViewer.p()); + + x3::Object spCommand(spCommon); + if( !spCommand.valid() ) + continue; + + AddRibbonButton(pRibbonBar, spCommon.p(), it->first); + + QWidget* pWidget = spCommand->getWndWidget(); + if( pWidget!=nullptr ) + { + QDockWidget* pDockWidget = qobject_cast(pWidget); + if( pDockWidget!=Q_NULLPTR ) + { + bool bVisible = pDockWidget->isVisible(); + if( pDockWidget->isAreaAllowed(Qt::LeftDockWidgetArea) ) + { + if( pFirstLeftDockWidget==Q_NULLPTR ) + pFrameWnd->addDockWidget(Qt::LeftDockWidgetArea, pDockWidget); + else + pFrameWnd->tabifyDockWidget(pFirstLeftDockWidget, pDockWidget); + pFirstLeftDockWidget = pDockWidget; + } + else if( pDockWidget->isAreaAllowed(Qt::RightDockWidgetArea) ) + { + if( pFirstRightDockWidget==Q_NULLPTR ) + pFrameWnd->addDockWidget(Qt::RightDockWidgetArea, pDockWidget); + else + pFrameWnd->tabifyDockWidget(pFirstRightDockWidget, pDockWidget); + pFirstRightDockWidget = pDockWidget; + } + else if( pDockWidget->isAreaAllowed(Qt::BottomDockWidgetArea) ) + { + if( pFirstBottomDockWidget==Q_NULLPTR ) + pFrameWnd->addDockWidget(Qt::BottomDockWidgetArea, pDockWidget); + else + pFrameWnd->tabifyDockWidget(pFirstBottomDockWidget, pDockWidget); + pFirstBottomDockWidget = pDockWidget; + } + else if( pDockWidget->isAreaAllowed(Qt::TopDockWidgetArea) ) + { + if( pFirstTopDockWidget==Q_NULLPTR ) + pFrameWnd->addDockWidget(Qt::TopDockWidgetArea, pDockWidget); + else + pFrameWnd->tabifyDockWidget(pFirstTopDockWidget, pDockWidget); + pFirstTopDockWidget = pDockWidget; + } + else + { + if( pFirstLeftDockWidget==Q_NULLPTR ) + pFrameWnd->addDockWidget(Qt::LeftDockWidgetArea, pDockWidget); + else + pFrameWnd->tabifyDockWidget(pFirstLeftDockWidget, pDockWidget); + pFirstLeftDockWidget = pDockWidget; + } + + if( !bVisible ) + pDockWidget->hide(); + } + } + + ret = true; + } + qDebug("CreateControl End\n"); + + /* + QRibbonPanel* pPanel = FindRibbonPanel(pRibbonBar, _T("主页"), _T("视图")); + if( pPanel!=NULL ) + pPanel->Add(new CMFCRibbonCheckBox(ID_VIEW_STATUS_BAR, _T("状态栏")));*/ + } + + return ret; +} + +bool CRibbonPluginManager::AddRibbonButton(QRibbonBar* pRibbonBar, IUIPlugin* pCommon, int id) +{ + if( pRibbonBar==nullptr || pCommon==nullptr ) + return false; + + x3::Object spCommand(pCommon); + if( !spCommand.valid() ) + return false; + + if( spCommand->getButtonWidget()==nullptr ) + return false; + + QString strCategory = pCommon->Category(); + if( strCategory.isEmpty() ) + strCategory = QObject::tr("Custom Plugin"); + + // 获取插件的标题 + QString strCaption = pCommon->Caption(); + if( strCaption.isEmpty() ) + strCaption = strCategory; + + // 根据范畴名称, 查找插件所属的QRibbonCategory + QRibbonCategory* pCategory = FindRibbonCategory(pRibbonBar, strCategory); + // 如果不存在该范畴,则自动创建 + if( pCategory==nullptr ) + pCategory = pRibbonBar->AddCategory(strCategory); + + if( pCommon->defaultCategory() ) + pRibbonBar->SetActiveCategory(pCategory); + + // 根据标题,查找插件所属的QRibbonPanel + QRibbonPanel* pPanel = FindRibbonPanel(pCategory, strCaption); + // 如果不存在,将自动创建 + if( pPanel==nullptr ) + pPanel = pCategory->addPanel(strCaption); + + pPanel->Add(spCommand->getButtonWidget()); + return true; +} + +QRibbonCategory* CRibbonPluginManager::FindRibbonCategory(QRibbonBar* pRibbonBar, const QString& strCategory) +{ + if( pRibbonBar==nullptr || strCategory.isEmpty() ) + return nullptr; + + // 根据范畴名称, 查找插件所属的QRibbonCategory + QRibbonCategory* pCategory = nullptr; + for( int i=0; iGetCategoryCount(); i++ ) + { + QRibbonCategory* pTmp = pRibbonBar->GetCategory(i); + if( pTmp==NULL ) + continue; + + if( strCategory.compare(pTmp->windowTitle(), Qt::CaseInsensitive)==0 ) + { + pCategory = pTmp; + break; + } + } + + return pCategory; +} + +QRibbonPanel* CRibbonPluginManager::FindRibbonPanel(QRibbonCategory* pCategory, const QString& strCaption) +{ + if( pCategory==nullptr || strCaption.isEmpty() ) + return nullptr; + + // 根据标题,查找插件所属的QRibbonPanel + QRibbonPanel* pPanel = nullptr; + for( int i=0; iGetPanelCount(); i++ ) + { + QRibbonPanel* pTmp = pCategory->GetPanel(i); + if( pTmp==nullptr ) + continue; + + if( strCaption.compare(pTmp->windowTitle(), Qt::CaseInsensitive)==0 ) + { + pPanel = pTmp; + break; + } + } + + return pPanel; +} + +QRibbonPanel* CRibbonPluginManager::FindRibbonPanel(QRibbonBar* pRibbonBar, const QString& strCategory, const QString& strCaption) +{ + if( pRibbonBar==nullptr || strCategory.isEmpty() || strCaption.isEmpty() ) + return nullptr; + + // 根据范畴名称, 查找插件所属的QRibbonCategory + QRibbonCategory* pCategory = FindRibbonCategory(pRibbonBar, strCategory); + if( pCategory==nullptr ) + return nullptr; + + // 根据标题,查找插件所属的QRibbonPanel + QRibbonPanel* pPanel = FindRibbonPanel(pCategory, strCaption); + return pPanel; +} + +void CRibbonPluginManager::DestroyControl() +{ + if(m_spViewer.valid()) + { + //x3::Object spViewer3D(m_spViewer); + //if(spViewer3D.valid()) + // spViewer3D->StopRender(); + } + m_spViewer = NULL; + UnloadPlugins(); +} + +void CRibbonPluginManager::SetViewer(x3::IObject* val) +{ + if( m_spViewer==val ) + return; + + m_spViewer = val; + x3::LockRW lockcls(m_mapPlugin.locker); + bool ret = false; + if( lockcls.canRead() ) + { + hash_map::iterator it = m_mapPlugin.begin(); + for( ; it!=m_mapPlugin.end(); it++ ) + { + x3::Object spCommon(it->second); + if( !spCommon.valid() ) + continue; + + spCommon->SetBuddy(m_spViewer.p()); + } + } +} diff --git a/CbersApp/ribbonpluginmanager.h b/CbersApp/ribbonpluginmanager.h new file mode 100644 index 0000000..790f2bc --- /dev/null +++ b/CbersApp/ribbonpluginmanager.h @@ -0,0 +1,41 @@ +#ifndef RIBBONPLUGINMANAGER_H +#define RIBBONPLUGINMANAGER_H +#include "pluginmanager.h" +#include "qribbonbar.h" +USING_NAMESPACE_CBERSUI + +#include +#include +#include + +class CRibbonPluginManager : public CPluginManager +{ +public: + CRibbonPluginManager(); + ~CRibbonPluginManager(void); + +public: + static CRibbonPluginManager* getInstance(); + static void Destroy(); + +private: + static CRibbonPluginManager* s_pManager; + +public: + bool Create(QMainWindow* pFrameWnd, QRibbonBar* pRibbonBar, QMdiArea* pMdiArea); + bool CreateViews(QMainWindow* pFrameWnd, QMdiArea* pMdiArea); + bool CreateControl(QRibbonBar* pRibbonBar, QMainWindow* pFrameWnd); + void SetViewer(x3::IObject* val); + void DestroyControl(); + +protected: + bool AddRibbonButton(QRibbonBar* pRibbonBar, IUIPlugin* pCommon, int id); + QRibbonCategory* FindRibbonCategory(QRibbonBar* pRibbonBar, const QString& lpszCategory); + QRibbonPanel* FindRibbonPanel(QRibbonCategory* pCategory, const QString& lpszCaption); + QRibbonPanel* FindRibbonPanel(QRibbonBar* pRibbonBar, const QString& lpszCategory, const QString& lpszCaption); + +protected: + x3::AnyObject m_spViewer; +}; + +#endif // RIBBONPLUGINMANAGER_H diff --git a/CbersPluginCore/CbersPluginCore.pro b/CbersPluginCore/CbersPluginCore.pro new file mode 100644 index 0000000..89b5d65 --- /dev/null +++ b/CbersPluginCore/CbersPluginCore.pro @@ -0,0 +1,41 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-01-04T16:43:03 +# +#------------------------------------------------- + +QT -= gui + +TARGET = CbersPluginCore +TEMPLATE = lib + +DEFINES += CBERSPLUGINCORE_LIBRARY + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + module.cpp \ + UICore.cpp + +HEADERS +=\ + cbersplugincore_global.h \ + UIPlugins.h \ + UICore.h \ + UIPluginsEvents.h + +PROJECT_PATH = $$PWD +SDK_PATH = $$PROJECT_PATH/../ +#TRANSLATION_LANGS = zh_CN +include( pluginconfig.pri ) + +QMAKE_POST_LINK += $$copyToDir(pluginconfig.pri, $$SDK_PATH/include/, $$PROJECT_PATH) + diff --git a/CbersPluginCore/UICore.cpp b/CbersPluginCore/UICore.cpp new file mode 100644 index 0000000..129d3e8 --- /dev/null +++ b/CbersPluginCore/UICore.cpp @@ -0,0 +1,114 @@ +#include "UICore.h" + +BEGIN_NAMESPACE_CBERSPLUGINS + +CUICore::CUICore() +{ + +} + +CUICore::~CUICore() +{ + clear(); +} + +long CUICore::size() +{ + x3::LockRW locker(m_mapData.locker); + return locker.canRead() ? m_mapData.size() : 0; +} + +x3::IObject* CUICore::Find(const char* key) +{ + x3::LockRW locker(m_mapData.locker); + IObject* ret = NULL; + if (locker.canRead()) + { + hash_map::const_iterator it = m_mapData.find(key); + ret = (it != m_mapData.end()) ? it->second.p() : NULL; + } + + return ret; +} + +bool CUICore::Add(const char* key, x3::IObject* obj) +{ + if( key==NULL || strlen(key)<=0 || obj==NULL ) + return false; + + x3::LockRW locker(m_mapData.locker, true); + bool ret = false; + if (locker.canWrite()) + { + m_mapData[key] = obj; + ret = true; + } + + return ret; +} + +bool CUICore::Remove(const char* key) +{ + x3::LockRW locker(m_mapData.locker, true); + bool ret = false; + if (locker.canWrite()) + { + hash_map::iterator it = m_mapData.find(key); + if( it!=m_mapData.end() ) + { + if( it->second.valid() ) + it->second.release(); + m_mapData.erase(it); + ret = true; + } + } + + return ret; +} + +bool CUICore::Remove(x3::IObject* obj) +{ + if( obj==nullptr ) + return false; + + x3::LockRW lockcls(m_mapData.locker, true); + bool ret = false; + if (lockcls.canWrite()) + { + hash_map::iterator it = m_mapData.begin(); + while (it != m_mapData.end()) + { + if (it->second == obj) + { + if( it->second.valid() ) + it->second.release(); + m_mapData.erase(it); + it = m_mapData.begin(); + ret = true; + } + else + { + ++it; + } + } + } + + return ret; +} + +void CUICore::clear() +{ + x3::LockRW lockcls(m_mapData.locker, true); + if (lockcls.canWrite()) + { + hash_map::iterator it = m_mapData.begin(); + for( ; it!=m_mapData.end(); it++ ) + { + if( it->second.valid() ) + it->second.release(); + } + m_mapData.clear(); + } +} + +END_NAMESPACE_CBERSPLUGINS diff --git a/CbersPluginCore/UICore.h b/CbersPluginCore/UICore.h new file mode 100644 index 0000000..6e459e8 --- /dev/null +++ b/CbersPluginCore/UICore.h @@ -0,0 +1,47 @@ +#pragma once +#include "UIPlugins.h" +#include "module/classmacro.h" +#include "utilfunc/lockrw.h" +#include + +#if !defined(_MSC_VER) || _MSC_VER >= 1700 +#include +#define hash_multimap std::unordered_multimap +#define hash_map std::unordered_map +#else +#if defined(_MSC_VER) && _MSC_VER > 1200 // VC8/9 + #include + using stdext::hash_multimap; + using stdext::hash_map; +#else // VC6, GCC or others + #define hash_multimap std::multimap + #define hash_map std::map +#endif +#endif + + +BEGIN_NAMESPACE_CBERSPLUGINS + +class CUICore : public IUICore +{ + X3BEGIN_CLASS_DECLARE(CUICore, clsidUICore) + X3DEFINE_INTERFACE_ENTRY(IUICore) + X3END_CLASS_DECLARE() + +public: + CUICore(); + virtual ~CUICore(); + +public: + virtual long size(); + virtual x3::IObject* Find(const char* key); + virtual bool Add(const char* key, x3::IObject* obj); + virtual bool Remove(const char* key); + virtual bool Remove(x3::IObject* obj); + virtual void clear(); + +protected: + x3::LockRW_ > m_mapData; +}; + +END_NAMESPACE_CBERSPLUGINS diff --git a/CbersPluginCore/UIPlugins.h b/CbersPluginCore/UIPlugins.h new file mode 100644 index 0000000..03775da --- /dev/null +++ b/CbersPluginCore/UIPlugins.h @@ -0,0 +1,111 @@ +#ifndef IPLUGIN_H +#define IPLUGIN_H +#include +#include +#include +#include +#include +#include "module/plugininc.h" +#include "objptr.h" +#include "cbersplugincore_global.h" + +BEGIN_NAMESPACE_CBERSPLUGINS +const char* const clsidUICore = "clsidUICore"; +class IUICore : public x3::IObject +{ + X3DEFINE_IID(IUICore); + +public: + virtual long size() = 0; + virtual x3::IObject* Find(const char* key) = 0; + virtual bool Add(const char* key, x3::IObject* obj) = 0; + virtual bool Remove(const char* key) = 0; + virtual bool Remove(x3::IObject* obj) = 0; + virtual void clear() = 0; +}; + +// 插件接口, 所有插件都必须继承该接口 +class IUIPlugin : public x3::IObject +{ + X3DEFINE_IID(IUIPlugin); + +public: + IUIPlugin() { m_spBuddy = NULL; m_defaultCategory = false; } + + const QString& Name() { return m_strName; } + void Name(const QString& val) { m_strName = val; } + + const QString& Caption() { return m_strCaption; } + void Caption(const QString& val) { m_strCaption = val; } + + const QString& Category() { return m_strCategory; } + void Category(const QString& val) { m_strCategory = val; } + + bool defaultCategory() { return m_defaultCategory; } + void defaultCategory(const bool val) { m_defaultCategory = val; } + + const QString& Tooltip() { return m_strTooltip; } + void Tooltip(const QString& val) { m_strTooltip = val; } + + const QString& Description() { return m_strDescription; } + void Description(const QString& val) { m_strDescription = val; } + + const QString& BitmapName() { return m_strBitmapName; } + void BitmapName(const QString& val) { m_strBitmapName = val; } + + virtual bool readConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ) + { + return true; + } + + virtual bool writeConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ) + { + return true; + } + + // 初始化 + virtual bool Initialize() = 0; + // 析构 + virtual bool UnInitialize() = 0; + virtual bool SetBuddy(x3::IObject* val) = 0;// { m_spBuddy = val; return true; } + +protected: + QString m_strName; + QString m_strCaption; + QString m_strCategory; + QString m_strTooltip; + QString m_strDescription; + QString m_strBitmapName; + x3::AnyObject m_spBuddy; + bool m_defaultCategory; +}; + +// 视图插件 +class IUIView : public x3::IObject +{ + X3DEFINE_IID(IUIView); + +public: + IUIView() { mMainWindow = nullptr; } + + virtual QWidget* getViewWidget() = 0; + virtual void setMainWindow(QMainWindow* win) { mMainWindow = win; } + virtual QMainWindow* mainWindow() { return mMainWindow; } + +protected: + QMainWindow* mMainWindow; +}; + +// 按钮插件 +class IUICommand : public x3::IObject +{ + X3DEFINE_IID(IUICommand); + +public: + virtual QWidget* getButtonWidget() { return 0; } + virtual QWidget* getWndWidget() { return 0; } +}; + + +END_NAMESPACE_CBERSPLUGINS +#endif // IPLUGIN_H diff --git a/CbersPluginCore/UIPluginsEvents.h b/CbersPluginCore/UIPluginsEvents.h new file mode 100644 index 0000000..92af4a5 --- /dev/null +++ b/CbersPluginCore/UIPluginsEvents.h @@ -0,0 +1,155 @@ +#pragma once +#include +#include "iobject.h" +#include "module/plugininc.h" +#include "observer/fireeventex.h" +#include "observer/fireobjeventex.h" +#include +#include +#include "cbersplugincore_global.h" + +BEGIN_NAMESPACE_CBERSPLUGINS + +#ifndef EVENT_NAMESPACE +#define EVENT_NAMESPACE "CbersEvent" +#endif + +X3DEFINE_OBJEVENT_4Break(EventMouseDown, long, long, long, long, EVENT_NAMESPACE); +X3DEFINE_OBJEVENT_4Break(EventMouseMove, long, long, long, long, EVENT_NAMESPACE); +X3DEFINE_OBJEVENT_4Break(EventMouseUp, long, long, long, long, EVENT_NAMESPACE); +X3DEFINE_OBJEVENT_4Break(EventButtonDblClk, long, long, long, long, EVENT_NAMESPACE); +X3DEFINE_OBJEVENT_5Break(EventMouseWheel, long, long, short, long, long, EVENT_NAMESPACE); +X3DEFINE_OBJEVENT_4Break(EventMouseHover, long, long, long, long, EVENT_NAMESPACE); +X3DEFINE_OBJEVENT_0Break(EventMouseLeave, EVENT_NAMESPACE); +X3DEFINE_OBJEVENT_3Break(EventContextMenu, long, long, long, EVENT_NAMESPACE); + +class IUIMouseResponse : x3::ObserverObject +{ +public: + IUIMouseResponse() + { + X3_REGISTER_OBSERVER_OBJECT(EventMouseDown, &IUIMouseResponse::OnMouseDown); + X3_REGISTER_OBSERVER_OBJECT(EventMouseMove, &IUIMouseResponse::OnMouseMove); + X3_REGISTER_OBSERVER_OBJECT(EventMouseUp, &IUIMouseResponse::OnMouseUp); + X3_REGISTER_OBSERVER_OBJECT(EventButtonDblClk, &IUIMouseResponse::OnButtonDblClk); + X3_REGISTER_OBSERVER_OBJECT(EventMouseWheel, &IUIMouseResponse::OnMouseWheel); + X3_REGISTER_OBSERVER_OBJECT(EventMouseHover, &IUIMouseResponse::OnMouseHover); + X3_REGISTER_OBSERVER_OBJECT(EventMouseLeave, &IUIMouseResponse::OnMouseLeave); + X3_REGISTER_OBSERVER_OBJECT(EventContextMenu, &IUIMouseResponse::OnContextMenu); + } + + virtual ~IUIMouseResponse() + { + x3::unregisterObserver(this); + } + +public: + virtual bool OnMouseDown(long button, long shift, long x, long y) { return true; } + virtual bool OnMouseMove(long button, long shift, long x, long y) { return true; } + virtual bool OnMouseUp(long button, long shift, long x, long y) { return true; } + virtual bool OnButtonDblClk(long button, long shift, long x, long y) { return true; } + virtual bool OnMouseWheel(long button, long shift, short zDelta, long x, long y) { return true; } + virtual bool OnMouseHover(long button, long shift, long x, long y) { return true; } + virtual bool OnMouseLeave() { return true; } + virtual bool OnContextMenu(long hWnd,long x, long y) { return true; } +}; + +X3DEFINE_OBJEVENT_2Break(EventKeyDown, long, long, EVENT_NAMESPACE); +X3DEFINE_OBJEVENT_2Break(EventKeyUp, long, long, EVENT_NAMESPACE); + +class IUIKeyResponse : public x3::ObserverObject +{ +public: + IUIKeyResponse() + { + X3_REGISTER_OBSERVER_OBJECT(EventKeyDown, &IUIKeyResponse::OnKeyDown); + X3_REGISTER_OBSERVER_OBJECT(EventKeyUp, &IUIKeyResponse::OnKeyUp); + } + + virtual ~IUIKeyResponse() + { + x3::unregisterObserver(this); + } + +public: + virtual bool OnKeyDown(long keyCode, long shift) { return false; } + virtual bool OnKeyUp(long keyCode, long shift) { return false; } +}; + +X3DEFINE_OBJEVENT_4Break(EventAnything, x3::IObject*, const std::string&, const QVariant&, const QVariant&, EVENT_NAMESPACE); + +class IAnythingEventObserver : public x3::ObserverObject +{ +public: + IAnythingEventObserver() + { + m_bRegister = false; + } + + virtual ~IAnythingEventObserver() + { + unregisterHandlers(); + } + +public: + // Event + virtual void registerHandlers() + { + if( m_bRegister ) + return; + + X3_REGISTER_OBSERVER_OBJECT(EventAnything, &IAnythingEventObserver::_OnAnything); + m_bRegister = true; + } + + virtual void unregisterHandlers() + { + if( !m_bRegister ) + return; + + x3::unregisterObserver(this); + m_bRegister = false; + } + + virtual void supportsEvent(const std::string& eventKey) + { + if( !eventKey.empty() ) + { + std::string lowerKey = eventKey; + std::transform(eventKey.begin(), eventKey.end(), lowerKey.begin(), tolower); + m_supportedEvents.insert(std::map::value_type(lowerKey, lowerKey)); + } + } + + virtual bool acceptsEvent(const std::string& eventKey) + { + if( eventKey.empty() ) + return false; + + if( m_supportedEvents.size()<=0 ) + return true; + + std::string lowerKey = eventKey; + std::transform(eventKey.begin(), eventKey.end(), lowerKey.begin(), tolower); + return m_supportedEvents.find(lowerKey)!=m_supportedEvents.end(); + } + + // Node Event + virtual bool OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam) { return true; } + +protected: + bool _OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam) + { + if( acceptsEvent(eventKey) ) + OnAnything(sender, eventKey, wParam, lParam); + + return true; + } + +protected: + bool m_bRegister; + std::map m_supportedEvents; +}; + +END_NAMESPACE_CBERSPLUGINS + diff --git a/CbersPluginCore/cbersplugincore_global.h b/CbersPluginCore/cbersplugincore_global.h new file mode 100644 index 0000000..474a000 --- /dev/null +++ b/CbersPluginCore/cbersplugincore_global.h @@ -0,0 +1,16 @@ +#ifndef CBERSPLUGINCORE_GLOBAL_H +#define CBERSPLUGINCORE_GLOBAL_H + +#include + +#if defined(CBERSPLUGINCORE_LIBRARY) +# define CBERSPLUGINCORESHARED_EXPORT Q_DECL_EXPORT +#else +# define CBERSPLUGINCORESHARED_EXPORT Q_DECL_IMPORT +#endif + +#define BEGIN_NAMESPACE_CBERSPLUGINS namespace Cbers { namespace Plugins { +#define END_NAMESPACE_CBERSPLUGINS } } +#define USING_NAMESPACE_CBERSPLUGINS using namespace Cbers::Plugins; + +#endif // CBERSPLUGINCORE_GLOBAL_H diff --git a/CbersPluginCore/module.cpp b/CbersPluginCore/module.cpp new file mode 100644 index 0000000..30fa751 --- /dev/null +++ b/CbersPluginCore/module.cpp @@ -0,0 +1,20 @@ +#include "module/plugininc.h" +#include "module/pluginimpl.h" +#include "module/modulemacro.h" +#include "observer/observerimpl.h" +#include "UICore.h" + +USING_NAMESPACE_CBERSPLUGINS + +XBEGIN_DEFINE_MODULE() + XDEFINE_CLASSMAP_ENTRY_Singleton(CUICore) +XEND_DEFINE_MODULE_DLL() + +OUTAPI bool x3InitializePlugin() +{ + return true; +} + +OUTAPI void x3UninitializePlugin() +{ +} diff --git a/CbersPluginCore/pluginconfig.pri b/CbersPluginCore/pluginconfig.pri new file mode 100644 index 0000000..0367344 --- /dev/null +++ b/CbersPluginCore/pluginconfig.pri @@ -0,0 +1,98 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-01-04T16:43:03 +# +#------------------------------------------------- +QT += core xml +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +TARGET_EXT = .pln + +OUTPUT_INCLUDE_PATH = $$SDK_PATH/include/PluginCore/ + +INCLUDEPATH += $$SDK_PATH/include +INCLUDEPATH += $$SDK_PATH/include/x3py +INCLUDEPATH += $$OUTPUT_INCLUDE_PATH +DEPENDPATH += $$SDK_PATH/include +DEPENDPATH += $$SDK_PATH/include/x3py +DEPENDPATH += $$OUTPUT_INCLUDE_PATH + +{ + CONFIG(debug, debug|release){ + DESTDIR = $$SDK_PATH/bin/debug/CbersPlugins + } + else{ + DESTDIR = $$SDK_PATH/bin/release/CbersPlugins + } +} + +!isEmpty(TRANSLATION_LANGS){ + TRANSLATION_DIR = $$SDK_PATH/i18n/ + TRANSLATIONS = + for(LANG, $$TRANSLATION_LANGS) { + TRANSLATIONS += $$TRANSLATION_DIR/$$TARGET_$$LANG.ts + } +} + +# Copies the given files to the destination directory +defineReplace(copyToDir) { + files = $$1 + DIR = $$2 + SRCDIR = $$3 + LINK = + + win32:DIR ~= s,/,\\,g + win32{ + LINK += if not exist $$quote($$DIR) ( $$QMAKE_MKDIR $$quote($$DIR) ) $$escape_expand(\\n\\t) + } + unix{ + LINK += $$QMAKE_MKDIR $$quote($$DIR) $$escape_expand(\\n\\t) + } + for(FILE, files) { + !isEmpty(SRCDIR){ + FILE = $$SRCDIR/$$FILE + } + win32:FILE ~= s,/,\\,g + LINK += $$QMAKE_COPY $$quote($$FILE) $$quote($$DIR) $$escape_expand(\\n\\t) + } + return($$LINK) +} + +!isEmpty(OUTPUT_INCLUDE_PATH){ + win32{ + OUTPUT_INCLUDE_PATH ~= s,/,\\,g + #QMAKE_POST_LINK += if exist $$quote($$OUTPUT_INCLUDE_PATH) ( rmdir /S /Q $$quote($$OUTPUT_INCLUDE_PATH) ) $$escape_expand(\\n\\t) + QMAKE_POST_LINK += cd $$quote($$PROJECT_PATH) $$escape_expand(\\n\\t) + } + unix{ + #QMAKE_POST_LINK += rm -rf $$quote($$OUTPUT_INCLUDE_PATH) $$escape_expand(\\n\\t) + QMAKE_POST_LINK += cd $$quote($$PROJECT_PATH) $$escape_expand(\\n\\t) + } + + QMAKE_POST_LINK += $$copyToDir($$HEADERS, $$OUTPUT_INCLUDE_PATH, $$PROJECT_PATH) +} + +# Auto Update And Release TRANSLATIONS +!isEmpty(TRANSLATION_DIR){ + win32:TRANSLATION_DIR ~= s,/,\\,g + win32{ + QMAKE_POST_LINK += if not exist $$quote($$TRANSLATION_DIR) ( $$QMAKE_MKDIR $$quote($$TRANSLATION_DIR) ) $$escape_expand(\\n\\t) + } + unix{ + QMAKE_POST_LINK += $$QMAKE_MKDIR -p $$quote($$TRANSLATION_DIR) $$escape_expand(\\n\\t) + } + QMAKE_POST_LINK += $(QTDIR)/bin/lupdate $$PROJECT_PATH/$$TARGET.pro $$escape_expand(\\n\\t) + QMAKE_POST_LINK += $(QTDIR)/bin/lrelease $$PROJECT_PATH/$$TARGET.pro $$escape_expand(\\n\\t) + + RELEASE_TRANSLATIONS = $$TRANSLATIONS + RELEASE_TRANSLATIONS ~= s,.ts,.qm,g + QMAKE_POST_LINK += $$copyToDir($$RELEASE_TRANSLATIONS, $$DESTDIR/../i18n/) +} + +unix{ + SRCEXT = .so + DSTEXT = .pln + QMAKE_POST_LINK += mv -f $$quote($$DESTDIR/lib$$TARGET$$SRCEXT) $$quote($$DESTDIR/$$TARGET$$DSTEXT) $$escape_expand(\\n\\t) +} diff --git a/CbersUI/CbersUI.pro b/CbersUI/CbersUI.pro new file mode 100644 index 0000000..2e627ae --- /dev/null +++ b/CbersUI/CbersUI.pro @@ -0,0 +1,103 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2016-07-12T17:18:16 +# +#------------------------------------------------- +QT += core gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TEMPLATE = lib +TARGET = CbersUI + +DEFINES += CBERSUI_LIBRARY + +SOURCES += \ + qribbonbar.cpp \ + qribboncategory.cpp \ + qribbonpanel.cpp \ + qribbonstylesheetmanager.cpp \ + qribbontabwidget.cpp \ + qtitlewidget.cpp \ + qseparator.cpp + +HEADERS +=\ + qribbonbar.h \ + qribboncategory.h \ + qribbonpanel.h \ + qribbonstylesheetmanager.h \ + qribbontabwidget.h \ + qtitlewidget.h \ + cbersui_global.h \ + qseparator.h + +{ + CONFIG(debug, debug|release){ + TARGET = $$join(TARGET,,,d) + + DESTDIR = $$PWD/../lib/debug + DLLDESTDIR = $$PWD/../bin/debug + } + else{ + DESTDIR = $$PWD/../lib/release + DLLDESTDIR = $$PWD/../bin/release + } +} + +RESOURCES += \ + cbersui.qrc + +TRANSLATION_DIR = $$PWD/../i18n/ +TRANSLATIONS = $$TRANSLATION_DIR/CbersUI_zh_CN.ts + +# Copies the given files to the destination directory +defineReplace(copyToDir) { + files = $$1 + DIR = $$2 + SRCDIR = $$3 + LINK = + + win32:DIR ~= s,/,\\,g + win32{ + LINK += if not exist $$quote($$DIR) ( $$QMAKE_MKDIR $$quote($$DIR) ) $$escape_expand(\\n\\t) + } + unix{ + LINK += $$QMAKE_MKDIR $$quote($$DIR) $$escape_expand(\\n\\t) + } + for(FILE, files) { + !isEmpty(SRCDIR){ + FILE = $$SRCDIR/$$FILE + } + win32:FILE ~= s,/,\\,g + LINK += $$QMAKE_COPY $$quote($$FILE) $$quote($$DIR) $$escape_expand(\\n\\t) + } + return($$LINK) +} + +SDK_PATH = $$PWD/../include/CbersUI/ +win32{ + SDK_PATH ~= s,/,\\,g + QMAKE_POST_LINK += if exist $$quote($$SDK_PATH) ( rmdir /S /Q $$quote($$SDK_PATH) ) $$escape_expand(\\n\\t) + QMAKE_POST_LINK += cd $$quote($$PWD) $$escape_expand(\\n\\t) +} +unix{ + QMAKE_POST_LINK += rm -rf $$quote($$SDK_PATH) $$escape_expand(\\n\\t) + QMAKE_POST_LINK += cd $$quote($$PWD) $$escape_expand(\\n\\t) +} + +QMAKE_POST_LINK += $$copyToDir($$HEADERS, $$SDK_PATH, $$PWD) + +# Auto Update And Release TRANSLATIONS +win32:TRANSLATION_DIR ~= s,/,\\,g +win32{ + QMAKE_POST_LINK += if not exist $$quote($$TRANSLATION_DIR) ( $$QMAKE_MKDIR $$quote($$TRANSLATION_DIR) ) $$escape_expand(\\n\\t) +} +unix{ + QMAKE_POST_LINK += $$QMAKE_MKDIR -p $$quote($$TRANSLATION_DIR) $$escape_expand(\\n\\t) +} + +QMAKE_POST_LINK += $(QTDIR)/bin/lupdate $$PWD/CbersUI.pro $$escape_expand(\\n\\t) +QMAKE_POST_LINK += $(QTDIR)/bin/lrelease $$PWD/CbersUI.pro $$escape_expand(\\n\\t) + +RELEASE_TRANSLATIONS = $$TRANSLATIONS +RELEASE_TRANSLATIONS ~= s,.ts,.qm,g +QMAKE_POST_LINK += $$copyToDir($$RELEASE_TRANSLATIONS, $$DLLDESTDIR/i18n/) diff --git a/CbersUI/Resource/office2007_black/AppCaption/Btn_HideElements.png b/CbersUI/Resource/office2007_black/AppCaption/Btn_HideElements.png new file mode 100644 index 0000000..b2353e2 Binary files /dev/null and b/CbersUI/Resource/office2007_black/AppCaption/Btn_HideElements.png differ diff --git a/CbersUI/Resource/office2007_black/AppCaption/Btn_ShowElements.png b/CbersUI/Resource/office2007_black/AppCaption/Btn_ShowElements.png new file mode 100644 index 0000000..ed179e8 Binary files /dev/null and b/CbersUI/Resource/office2007_black/AppCaption/Btn_ShowElements.png differ diff --git a/CbersUI/Resource/office2007_black/AppCaption/SysBtn_Close.png b/CbersUI/Resource/office2007_black/AppCaption/SysBtn_Close.png new file mode 100644 index 0000000..af76ba0 Binary files /dev/null and b/CbersUI/Resource/office2007_black/AppCaption/SysBtn_Close.png differ diff --git a/CbersUI/Resource/office2007_black/AppCaption/SysBtn_Maximize.png b/CbersUI/Resource/office2007_black/AppCaption/SysBtn_Maximize.png new file mode 100644 index 0000000..21f9cfb Binary files /dev/null and b/CbersUI/Resource/office2007_black/AppCaption/SysBtn_Maximize.png differ diff --git a/CbersUI/Resource/office2007_black/AppCaption/SysBtn_Minimize.png b/CbersUI/Resource/office2007_black/AppCaption/SysBtn_Minimize.png new file mode 100644 index 0000000..2ba09c0 Binary files /dev/null and b/CbersUI/Resource/office2007_black/AppCaption/SysBtn_Minimize.png differ diff --git a/CbersUI/Resource/office2007_black/AppCaption/SysBtn_Restore.png b/CbersUI/Resource/office2007_black/AppCaption/SysBtn_Restore.png new file mode 100644 index 0000000..567e921 Binary files /dev/null and b/CbersUI/Resource/office2007_black/AppCaption/SysBtn_Restore.png differ diff --git a/CbersUI/Resource/office2007_black/Black/caret-down_ffffff_14.png b/CbersUI/Resource/office2007_black/Black/caret-down_ffffff_14.png new file mode 100644 index 0000000..6add5a4 Binary files /dev/null and b/CbersUI/Resource/office2007_black/Black/caret-down_ffffff_14.png differ diff --git a/CbersUI/Resource/office2007_black/Black/caret-right_ffffff_14.png b/CbersUI/Resource/office2007_black/Black/caret-right_ffffff_14.png new file mode 100644 index 0000000..3c46502 Binary files /dev/null and b/CbersUI/Resource/office2007_black/Black/caret-right_ffffff_14.png differ diff --git a/CbersUI/Resource/office2007_black/Black/check.png b/CbersUI/Resource/office2007_black/Black/check.png new file mode 100644 index 0000000..0726b78 Binary files /dev/null and b/CbersUI/Resource/office2007_black/Black/check.png differ diff --git a/CbersUI/Resource/office2007_black/Black/cross.svg b/CbersUI/Resource/office2007_black/Black/cross.svg new file mode 100644 index 0000000..2e149f2 --- /dev/null +++ b/CbersUI/Resource/office2007_black/Black/cross.svg @@ -0,0 +1,59 @@ + + + + + + + + image/svg+xml + + + + + + + + diff --git a/CbersUI/Resource/office2007_black/Black/down_arrow.png b/CbersUI/Resource/office2007_black/Black/down_arrow.png new file mode 100644 index 0000000..db581cb Binary files /dev/null and b/CbersUI/Resource/office2007_black/Black/down_arrow.png differ diff --git a/CbersUI/Resource/office2007_black/Black/eye-blocked.svg b/CbersUI/Resource/office2007_black/Black/eye-blocked.svg new file mode 100644 index 0000000..fbea68c --- /dev/null +++ b/CbersUI/Resource/office2007_black/Black/eye-blocked.svg @@ -0,0 +1,67 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/CbersUI/Resource/office2007_black/Black/eye.svg b/CbersUI/Resource/office2007_black/Black/eye.svg new file mode 100644 index 0000000..a8b2113 --- /dev/null +++ b/CbersUI/Resource/office2007_black/Black/eye.svg @@ -0,0 +1,56 @@ + + + + + + + + image/svg+xml + + + + + + + + diff --git a/CbersUI/Resource/office2007_black/Black/up_arrow.png b/CbersUI/Resource/office2007_black/Black/up_arrow.png new file mode 100644 index 0000000..8673611 Binary files /dev/null and b/CbersUI/Resource/office2007_black/Black/up_arrow.png differ diff --git a/CbersUI/Resource/office2007_black/office2007_black.qss b/CbersUI/Resource/office2007_black/office2007_black.qss new file mode 100644 index 0000000..d5f523b --- /dev/null +++ b/CbersUI/Resource/office2007_black/office2007_black.qss @@ -0,0 +1,776 @@ +QWidget +{ + color: #aaa; + background-color: #323232; +} + + +QWidget:item:hover +{ + background-color: #507098; + color: #aaa; +} + +QWidget:item:selected +{ + background-color: #507098; +} + +QMenuBar { + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(231, 231, 231, 255), stop:1 rgba(208, 208, 208, 255)); +} + +QMenuBar::item +{ + background: transparent; + color: #000000; +} + +QMenuBar::item:selected +{ + background: rgb(122, 122, 122); + color: #FFFFFF; +} + +QMenuBar::item:pressed +{ + background: rgb(122, 122, 122); + color: #FFFFFF; + margin-bottom:-1px; + padding-bottom:1px; +} + +QAbstractSpinBox { + padding-right: 0px; /* make room for the arrows */ + border: 1px solid #222; + background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #565656, stop: 0.1 #525252, stop: 0.5 #4e4e4e, stop: 0.9 #4a4a4a, stop: 1 #464646); + } + + QAbstractSpinBox::up-button { + subcontrol-origin: border; + subcontrol-position: top right; + + width: 16px; + image: url(:/office2007/Resource/office2007_black/Black/up_arrow.png) 1; + } + + QAbstractSpinBox::down-button { + subcontrol-origin: border; + subcontrol-position: bottom right; + + width: 16px; + image: url(:/office2007/Resource/office2007_black/Black/down_arrow.png); + } + + +/* ==================================================================================== */ +/* MENU */ +/* ==================================================================================== */ + +QMenu +{ + background: rgb(240, 240, 240); + border: 2px solid rgb(204, 204, 204); +} + +QMenu::item +{ + background: rgb(240, 240, 240); + color: #000000; +} + +QMenu::item:disabled +{ + color: #555; + background: rgb(240, 240, 240); +} + + +QMenu::item:selected +{ + background: rgb(144, 200, 246); +} + +QMenu::separator { + height: 2px; + background: #555; +} + +QWidget:disabled +{ + color: #404040; + background-color: #323232; +} + +QLineEdit +{ + padding: 1px; + border: 1px solid #111; + background-color: #888; + color: #111; +} + +QPushButton +{ + color: #b1b1b1; + border-width: 1px; + border-color: #1e1e1e; + border-style: solid; + padding: 3px; + font-size: 12px; + padding-left: 5px; + padding-right: 5px; + background: transparent; +} + +QToolButton +{ + color: #b1b1b1; + padding: 3px 5px 3px 5px; + font-size: 12px; + border-width: 1px; + border-color: #1e1e1e; + border-style: solid; + background-color:none; +} +QToolButton:disabled{ + background-color:none; +} +QToolButton:checked{ + background-color:#507098; +} + + +QToolButton[popupMode="1"] +{ + padding-right: 18px; +} +QToolButton::menu-button { + width: 14px; + border-width: 1px; + border-color: none; + background: none; +} +QToolButton::hover, QToolButton::menu-button::hover +{ + border-width: 1px; + border-color: #1e1e1e; + border-style: solid; + background-color:#535353; +} +QToolButton::menu-arrow +{ + image: url(:/office2007/Resource/office2007_black/Black/down_arrow.png); +} +QToolBar QToolButton, QToolButton::menu-button +{ + border:0; + background-color: none; +} + +/* ==================================================================================== */ +/* COMBO BOX */ +/* ==================================================================================== */ + +QComboBox { + selection-background-color: #0d7200; + background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #565656, stop: 0.1 #525252, stop: 0.5 #4e4e4e, stop: 0.9 #4a4a4a, stop: 1 #464646); + border-style: solid; + border: 1px solid #1e1e1e; + padding: 3px 3px 3px 3px; +} + + +QComboBox:hover,QPushButton:hover { + background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #565656, + stop: 0.1 #525252, + stop: 0.5 #4e4e4e, + stop: 0.9 #4a4a4a, + stop: 1 #464646); +} + +QComboBox:on { + padding-top: 1px; + padding-left: 3px; + background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #555, + stop: 0.1 #4C4C4C, + stop: 0.5 #464646, + stop: 0.9 #414141, + stop: 1 #444); + selection-background-color: #0d7200; +} + +QComboBox:editable { + background: #323232; +} + +QComboBox QAbstractItemView { + border: 1px solid #222; + selection-background-color: #507098; +} + +QComboBox::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + width: 15px; + border: 0px; + } + +QComboBox::down-arrow +{ + image: url(:/office2007/Resource/office2007_black/Black/down_arrow.png); +} + + +QLineEdit:focus +{ + border: 2px solid QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffa02f, stop: 1 #d7801a); +} + + +QTextEdit:focus +{ + border: 2px solid QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffa02f, stop: 1 #d7801a); +} + +/* ==================================================================================== */ +/* SCROLL BAR */ +/* ==================================================================================== */ + +QScrollBar:horizontal { + background-color: #333; + height: 8px; + margin: 0px; + padding: 0px; +} + +QScrollBar::handle:horizontal { + border: 1px solid #111; + background: #535353; +} + +QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal, +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { + width: 0px; + background: transparent; +} + +QScrollBar:vertical { + background-color: #333; + width: 8px; + margin: 0; +} + +QScrollBar::handle:vertical { + border: 1px solid #111; + background: #535353; +} + +QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical, +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + height: 0px; + background: transparent; +} + + +QTextEdit +{ + background-color: #242424; +} + +QPlainTextEdit +{ + background-color: #242424; +} + +QSizeGrip +{ + width: 1px; +} + +QHeaderView::section +{ + /*background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0 #616161, stop: 0.5 #505050, stop: 0.6 #434343, stop:1 #656565);*/ + color: white; + padding-left: 4px; + border: 1px solid #6c6c6c; +} +QDockWidget +{ + titlebar-close-icon: url(:/office2007/Resource/office2007_black/Black/cross.svg); +} + +QDockWidget::separator +{ + border: 1px solid red; +} + +QDockWidget::title +{ + text-align: center; + spacing: 3px; /* spacing between items in the tool bar */ + background-color: #323232; + font-weight: bold; +} + +QDockWidget::close-button, QDockWidget::float-button +{ + text-align: center; + spacing: 1px; /* spacing between items in the tool bar */ +} + +QDockWidget::close-button:hover, QDockWidget::float-button:hover +{ + background: #242424; +} + +QDockWidget::close-button:pressed, QDockWidget::float-button:pressed +{ + padding: 1px -1px -1px 1px; +} + +QMainWindow::separator +{ + /*background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0 #161616, stop: 0.5 #151515, stop: 0.6 #212121, stop:1 #343434);*/ + color: white; + padding-left: 4px; + border: 0px solid #4c4c4c; + spacing: 3px; /* spacing between items in the tool bar */ +} + +QMainWindow::separator:hover +{ + + /*background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0 #d7801a, stop:0.5 #b56c17 stop:1 #ffa02f);*/ + color: white; + padding-left: 4px; + border: 1px solid #6c6c6c; + spacing: 3px; /* spacing between items in the tool bar */ +} + +QToolBar { + /*background: #323232;*/ + background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(123, 123, 123, 255), stop:0.2 rgba(97, 97, 97, 255), stop:1 rgba(76, 76, 76, 255)); + border: 1px solid #323232; + font-weight: bold; +} + +QToolBar::handle:horizontal +{ + image: url(:/qss_icons/rc/Hmovetoolbar.png); +} + +QToolBar::handle:vertical +{ + image: url(:/qss_icons/rc/Vmovetoolbar.png); +} + +QToolBar::separator:horizontal +{ + image: url(:/qss_icons/rc/Hsepartoolbar.png); +} + +QToolBar::separator:vertical +{ + image: url(:/qss_icons/rc/Vsepartoolbars.png); +} + +QMenu::separator +{ + height: 2px; + /* + background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0 #161616, stop: 0.5 #151515, stop: 0.6 #212121, stop:1 #343434); + */ + color: white; + padding-left: 4px; + margin-left: 10px; + margin-right: 5px; +} + +QProgressBar +{ + border: 2px solid grey; + text-align: center; +} + +QProgressBar::chunk +{ + background-color: #d7801a; + width: 2.15px; + margin: 0.5px; +} + +QTabBar::tab { + color: #b1b1b1; + border: 1px solid #444; + border-bottom-style: none; + background-color: #323232; + padding-left: 10px; + padding-right: 10px; + padding-top: 3px; + padding-bottom: 2px; + margin-right: -1px; +} + +QTabWidget::pane { + border: 1px solid #444; + top: 1px; +} + +QTabBar::tab:last +{ + margin-right: 0; /* the last selected tab has nothing to overlap with on the right */ +} + +QTabBar::tab:first:!selected +{ + margin-left: 0px; /* the last selected tab has nothing to overlap with on the right */ +} + +QTabBar::tab:bottom { + border-bottom: 1px solid rgb(190, 190, 190); +} + +QTabBar::tab:!selected +{ + margin-top: 5px; +} + +QTabBar::tab:selected +{ + margin-bottom: 0px; +} + +QTabBar::tab:!selected:hover +{ + /*border-top: 2px solid #0d7200; + padding-bottom: 3px;*/ + /*background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:1 #212121, stop:0.4 #343434, stop:0.2 #343434, stop:0.1 #ffaa00);*/ +} + +QGroupBox::indicator:hover, +QCheckBox::indicator:hover, +QRadioButton::indicator:hover +{ + border: 1px solid #0d7200; +} + +/* ==================================================================================== */ +/* GROUP */ +/* ==================================================================================== */ + +QGroupBox::title { color:#FFFFFF; } + +QGroupBox::indicator:unchecked { + background-color: #535353; +} + +QGroupBox::indicator:checked { + background-color: #0f6e00; +} +/* ==================================================================================== */ +/* RADIO BUTTON */ +/* ==================================================================================== */ + +QRadioButton::indicator:unchecked { + background-color: #535353; + border-radius:10px; +} + +QRadioButton::indicator:checked { + background-color: #0f6e00; + border-radius:10px; +} + +/* ==================================================================================== */ +/* CHECKBOX */ +/* ==================================================================================== */ + +QCheckBox::indicator:unchecked { + background-color: #535353; +} + +QCheckBox::indicator:checked { + background-color: #0f6e00; +} + +/* ==================================================================================== */ +/* SLIDER */ +/* ==================================================================================== */ + +QSlider::groove:horizontal, +QSlider::groove:vertical { + border: 1px solid #262626; + height: 8px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */ + background-color: #535353; + margin: 2px 0; +} + +QSlider::handle:horizontal { + background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f); + border: 1px solid #5c5c5c; + width: 18px; + margin: -2px 0; /* handle is placed by default on the contents rect of the groove. Expand outside the groove */ + border-radius: 3px; +} +QSlider::handle:vertical { + background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f); + border: 1px solid #5c5c5c; + height: 18px; + margin: -2px 0; /* handle is placed by default on the contents rect of the groove. Expand outside the groove */ + border-radius: 3px; +} + +/* ==================================================================================== */ +/* OTHER */ +/* ==================================================================================== */ + +QAbstractItemView +{ + background-color: #222; + alternate-background-color: #323232; + color: silver; + border: none; + border-radius: 3px; + padding: 1px; +} + +QAbstractItemView::selected { + border: 0px; + outline: none; +} + +/* ==================================================================================== */ +/* TREE VIEW */ +/* ==================================================================================== */ + +QTreeView { + border: 0.5px solid rgba(108,108,108,75); +} + +QTreeView::item, QTreeView::branch { + background: transparent; + color: #DDD; +} + +QTreeView::item:hover, QTreeView::branch:hover { + background-color: #535353; + color: #DDD; +} + +QTreeView::item:selected, QTreeView::branch:selected { + background-color: #0f6e00; + color: #DDD; +} + + +QTreeView::branch:has-children:!has-siblings:closed, +QTreeView::branch:closed:has-children:has-siblings { + border-image: none; + image: url(:/office2007/Resource/office2007_black/Black/caret-right_ffffff_14.png); +} + +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings { + border-image: none; + image: url(:/office2007/Resource/office2007_black/Black/caret-down_ffffff_14.png); +} + +QgsLayerTreeView +{ +} + +QgsLayerTreeView::item, +QTreeView#viewGraduated::item, +QTreeView#viewCategories::item, +QTreeView#viewRules::item +{ + border-top: 0.5px solid rgba(108,108,108,50); + border-bottom: 0.5px solid rgba(108,108,108,50); + padding: 3px; +} + +QgsLayerTreeView::indicator:unchecked, +QTreeView#viewGraduated::indicator:unchecked, +QTreeView#viewCategories::indicator:unchecked, +QTreeView#viewRules::indicator:unchecked +{ + image: url(:/office2007/Resource/office2007_black/Black/eye-blocked.svg); +} + +QgsLayerTreeView::indicator:checked, +QTreeView#viewGraduated::indicator:checked, +QTreeView#viewCategories::indicator:checked, +QTreeView#viewRules::indicator:checked +{ + image: url(:/office2007/Resource/office2007_black/Black/eye.svg); +} + +/* ==================================================================================== */ +/* TABLE VIEW */ +/* ==================================================================================== */ + +QHeaderView { +} + +QHeaderView::section { + background: transparent; + background-color: #323232; + color: #777; + border-right: 0px solid #777; + border-top: 0px solid #777; + padding: 0 0 2px 3px +} + +QWidget#QRibbonBar{ + background-color: transparent; +} + +QPushButton#Btn_ShowElements {border-image: url(:/office2007/Resource/office2007_black/AppCaption/Btn_ShowElements.png);} +QPushButton#Btn_ShowElements:hover {background-color: rgba(229, 229, 229, 255);} +QPushButton#Btn_ShowElements:pressed {background-color: rgba(202, 202, 202, 255);} +QPushButton#Btn_HideElements {border-image: url(:/office2007/Resource/office2007_black/AppCaption/Btn_HideElements.png);} +QPushButton#Btn_HideElements:hover {background-color: rgba(229, 229, 229, 255);} +QPushButton#Btn_HideElements:pressed {background-color: rgba(202, 202, 202, 255);} +QPushButton#SysBtn_Minimize {border-image: url(:/office2007/Resource/office2007_black/AppCaption/SysBtn_Minimize.png);} +QPushButton#SysBtn_Minimize:hover {background-color: rgba(229, 229, 229, 255);} +QPushButton#SysBtn_Minimize:pressed {background-color: rgba(202, 202, 202, 255);} +QPushButton#SysBtn_Restore {border-image: url(:/office2007/Resource/office2007_black/AppCaption/SysBtn_Restore.png);} +QPushButton#SysBtn_Restore:hover {background-color: rgba(229, 229, 229, 255);} +QPushButton#SysBtn_Restore:pressed {background-color: rgba(202, 202, 202, 255);} +QPushButton#SysBtn_Maximize {border-image: url(:/office2007/Resource/office2007_black/AppCaption/SysBtn_Maximize.png);} +QPushButton#SysBtn_Maximize:hover {background-color: rgba(229, 229, 229, 255);} +QPushButton#SysBtn_Maximize:pressed {background-color: rgba(202, 202, 202, 255);} +QPushButton#SysBtn_Close {border-image: url(:/office2007/Resource/office2007_black/AppCaption/SysBtn_Close.png);} +QPushButton#SysBtn_Close:hover {background-color: rgba(232, 17, 35, 255);} +QPushButton#SysBtn_Close:pressed {background-color: rgba(241, 112, 122, 255);} + +QTabWidget#QRibbonTabWidget { + padding: 0px 0px 0px 0px; + background-color: transparent; /* qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(215, 218, 223, 255), stop:0.2 rgba(180, 187, 197, 255), stop:1 rgba(230, 240, 241, 255));*/ + border:0; + min-width: 100%; + left: 0px; + right: 0px; +} + +QTabWidget#QRibbonTabWidget QWidget#qt_tabwidget_stackedwidget{ + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(215, 218, 223, 255), stop:0.2 rgba(180, 187, 197, 255), stop:1 rgba(230, 240, 241, 255)); +} + +QTabWidget#QRibbonTabWidget::pane { + background-color: transparent; /* qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(215, 218, 223, 255), stop:0.2 rgba(180, 187, 197, 255), stop:1 rgba(230, 240, 241, 255)); */ + border: 1px solid rgb(228, 231, 234); + border-radius: 5px; + padding: 1px; +} + +QTabWidget#QRibbonTabWidget::tab-bar { + left: 5px; + right: 5px; + background-color: transparent; + min-width: 100%; +} +QTabWidget#QRibbonTabWidget QTabBar::tab { + margin-top: 5px; + min-width: 60px; + background-color: transparent; + height: 25px; + border: 0; + color: #FFFFFF; + margin-left: 2px; + margin-right: 2px; + padding: 0px 0px 0px 0px; +} +QTabWidget#QRibbonTabWidget QTabBar::tab:!selected{ + border: 0px; + background-color: transparent; +} +QTabWidget#QRibbonTabWidget QTabBar::tab:selected{ + border: 1px solid rgb(239, 240, 242); + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(215, 218, 223, 255), stop:0.2 rgba(180, 187, 197, 255), stop:1 rgba(230, 240, 241, 255)); + border-bottom: 1px solid rgb(213, 214, 200); + border-top-left-radius: 4px; + border-top-right-radius: 4px; + color: #000000; + font-weight: bold; +} +QTabWidget#QRibbonTabWidget QTabBar::tab:!selected:hover{ + border: 1px solid #99BBE8; + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(151, 149, 148, 255), stop:0.2 rgba(121, 111, 91, 255), stop:1 rgba(114, 108, 93, 255)); + border-top-left-radius: 4px; + border-top-right-radius: 4px; + color: #FFFFFF; + border-bottom: 0px solid rgba(255, 197, 115, 168); +} +QTabWidget#QRibbonTabWidget QTabBar::tab:selected:hover { + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(215, 218, 223, 255), stop:0.2 rgba(180, 187, 197, 255), stop:1 rgba(230, 240, 241, 255)); + border-color: rgba(237, 194, 39, 255); +} +QTabWidget#QRibbonTabWidget QTabBar::tab:first { + margin-left: 4px; +} +QTabWidget#QRibbonTabWidget QTabBar::tab:last { + margin-right: 4px; +} +QGroupBox#QRibbonPanelGroupBox { + background-color: transparent; /* qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(215, 218, 223, 255), stop:0.2 rgba(180, 187, 197, 255), stop:1 rgba(230, 240, 241, 255)); */ + border: 1px solid rgb(146, 149, 152); + border-radius: 3px; + padding: 0px 0px 0px 0px; +} + +QGroupBox#QRibbonPanelGroupBox:hover { + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(247, 248, 249, 255), stop:0.2 rgba(229, 231, 235, 255), stop:1 rgba(247, 247, 247, 255)); + border: 1px solid rgb(146, 149, 152); + border-radius: 3px; +} + +QGroupBox#QRibbonPanelGroupBox QToolButton{ + padding: 0; + color: #000000; + border:0; + background-color: transparent; +} + +QGroupBox#QRibbonPanelGroupBox QToolButton:disabled{ + color: #808080; +} + +QGroupBox#QRibbonPanelGroupBox QToolButton:!checked:hover{ + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 253, 223, 255), stop:0.2 rgba(255, 215, 72, 255), stop:1 rgba(255, 231, 150, 255)); +} + +QGroupBox#QRibbonPanelGroupBox QToolButton:checked{ + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(252, 211, 166, 255), stop:0.2 rgba(248, 141, 40, 255), stop:1 rgba(253, 228, 152, 255)); +} + +QGroupBox#QRibbonPanelGroupBox QToolButton:checked:hover{ + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(249, 183, 110, 255), stop:0.2 rgba(230, 129, 50, 255), stop:1 rgba(253, 206, 100, 255)); +} + +QWidget#QRibbonPanelFooter { + background-color: rgb(171, 172, 172); +} +QLabel#QRibbonPanelFooterLabel { + color: #FFFFFF; + background-color: transparent; +} +QLabel#sysTitle { + color: #FFFFFF; + background-color: transparent; +} +QPushButton#sysIconLabel { + background-color: rgba(229, 229, 229, 0); +} +QPushButton#sysIconLabel:hover { + background-color: rgba(229, 229, 229, 255); +} +QPushButton#sysIconLabel:pressed { + background-color: rgba(202, 202, 202, 255); +} +QPushButton#sysIconLabel::menu-indicator{ + image:none; +} diff --git a/CbersUI/Resource/office2007_blue/AppCaption/Btn_HideElements.png b/CbersUI/Resource/office2007_blue/AppCaption/Btn_HideElements.png new file mode 100644 index 0000000..b2353e2 Binary files /dev/null and b/CbersUI/Resource/office2007_blue/AppCaption/Btn_HideElements.png differ diff --git a/CbersUI/Resource/office2007_blue/AppCaption/Btn_ShowElements.png b/CbersUI/Resource/office2007_blue/AppCaption/Btn_ShowElements.png new file mode 100644 index 0000000..ed179e8 Binary files /dev/null and b/CbersUI/Resource/office2007_blue/AppCaption/Btn_ShowElements.png differ diff --git a/CbersUI/Resource/office2007_blue/AppCaption/SysBtn_Close.png b/CbersUI/Resource/office2007_blue/AppCaption/SysBtn_Close.png new file mode 100644 index 0000000..af76ba0 Binary files /dev/null and b/CbersUI/Resource/office2007_blue/AppCaption/SysBtn_Close.png differ diff --git a/CbersUI/Resource/office2007_blue/AppCaption/SysBtn_Maximize.png b/CbersUI/Resource/office2007_blue/AppCaption/SysBtn_Maximize.png new file mode 100644 index 0000000..21f9cfb Binary files /dev/null and b/CbersUI/Resource/office2007_blue/AppCaption/SysBtn_Maximize.png differ diff --git a/CbersUI/Resource/office2007_blue/AppCaption/SysBtn_Minimize.png b/CbersUI/Resource/office2007_blue/AppCaption/SysBtn_Minimize.png new file mode 100644 index 0000000..2ba09c0 Binary files /dev/null and b/CbersUI/Resource/office2007_blue/AppCaption/SysBtn_Minimize.png differ diff --git a/CbersUI/Resource/office2007_blue/AppCaption/SysBtn_Restore.png b/CbersUI/Resource/office2007_blue/AppCaption/SysBtn_Restore.png new file mode 100644 index 0000000..567e921 Binary files /dev/null and b/CbersUI/Resource/office2007_blue/AppCaption/SysBtn_Restore.png differ diff --git a/CbersUI/Resource/office2007_blue/office2007_blue.qss b/CbersUI/Resource/office2007_blue/office2007_blue.qss new file mode 100644 index 0000000..eb4118b --- /dev/null +++ b/CbersUI/Resource/office2007_blue/office2007_blue.qss @@ -0,0 +1,125 @@ +QMainWindow#QRibbonMainWindow{ + background-color: #BEDAFE; + border: 1px solid rgba(24, 131, 215, 255); + min-width: 100%; +} +QWidget#QRibbonTitleWidget { + background-color: #ffffff; +} + +QPushButton#Btn_ShowElements {border-image: url(:/office2007/Resource/office2007_blue/AppCaption/Btn_ShowElements.png);} +QPushButton#Btn_HideElements {border-image: url(:/office2007/Resource/office2007_blue/AppCaption/Btn_HideElements.png);} +QPushButton#SysBtn_Minimize {border-image: url(:/office2007/Resource/office2007_blue/AppCaption/SysBtn_Minimize.png);} +QPushButton#SysBtn_Minimize:hover {background-color: rgba(229, 229, 229, 255);} +QPushButton#SysBtn_Minimize:pressed {background-color: rgba(202, 202, 202, 255);} +QPushButton#SysBtn_Restore {border-image: url(:/office2007/Resource/office2007_blue/AppCaption/SysBtn_Restore.png);} +QPushButton#SysBtn_Restore:hover {background-color: rgba(229, 229, 229, 255);} +QPushButton#SysBtn_Restore:pressed {background-color: rgba(202, 202, 202, 255);} +QPushButton#SysBtn_Maximize {border-image: url(:/office2007/Resource/office2007_blue/AppCaption/SysBtn_Maximize.png);} +QPushButton#SysBtn_Maximize:hover {background-color: rgba(229, 229, 229, 255);} +QPushButton#SysBtn_Maximize:pressed {background-color: rgba(202, 202, 202, 255);} +QPushButton#SysBtn_Close {border-image: url(:/office2007/Resource/office2007_blue/AppCaption/SysBtn_Close.png);} +QPushButton#SysBtn_Close:hover {background-color: rgba(232, 17, 35, 255);} +QPushButton#SysBtn_Close:pressed {background-color: rgba(241, 112, 122, 255);} + +QTabWidget#QRibbonTabWidget::pane { + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(216, 229, 247, 255), stop:0.2 rgba(204, 220, 242, 255), stop:0.8 rgba(178, 202, 234, 255), stop:1 rgba(207, 224, 245, 255)); + border: 1px solid #90B5E4; + border-radius: 5px; + padding: 1px; +} +QTabWidget#QRibbonTabWidget { + background-color: #BEDAFE; + min-width: 100%; + left: 0px; + right: 0px; +} +QTabWidget#QRibbonTabWidget::tab-bar { + left: 5px; + right: 5px; + background-color: #BEDAFE; + min-width: 100%; +} +QTabWidget#QRibbonTabWidget QTabBar::tab { + margin-top: 5px; + min-width: 55px; + background-color: #BEDAFE; + height: 25px; + border: 1px solid #BEDAFE; + color: #4B7CB4; + border-bottom: 0px solid #BEDAFE; + margin-left: 2px; + margin-right: 2px; +} +QTabWidget#QRibbonTabWidget QTabBar::tab:!selected{ + border: 0px; + background-color: transparent; +} +QTabWidget#QRibbonTabWidget QTabBar::tab:selected{ + border: 1px solid #90B5E4; + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.1 rgba(239, 244, 251, 255), stop:1 rgba(231, 239, 249, 255)); + border-bottom: 1px solid #E1EAF5; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + color: #4B7CB4; +} +QTabWidget#QRibbonTabWidget QTabBar::tab:hover{ + border: 1px solid #99BBE8; + background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.75, fx:0.5, fy:-0.5, stop:0 #BEDAFE, stop:0.5 #BEDAFE, stop:1 rgba(255, 197, 115, 168)); + border-top-left-radius: 4px; + border-top-right-radius: 4px; + color: #4B7CB4; + border-bottom: 0px solid rgba(255, 197, 115, 168); +} +QTabWidget#QRibbonTabWidget QTabBar::tab:selected:hover { + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:0.1 rgba(239, 244, 251, 255), stop:1 rgba(231, 239, 249, 255)); + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-style: solid; + border-width: 1px; + border-color: rgba(255, 197, 115, 150); + border-bottom: 1px solid #E1EAF5; +} +QTabWidget#QRibbonTabWidget QTabBar::tab:first { + margin-left: 4px; +} +QTabWidget#QRibbonTabWidget QTabBar::tab:last { + margin-right: 4px; +} +QTabWidget#QRibbonTabWidget QGroupBox::title { + position: absolute; + subcontrol-origin: padding; + subcontrol-position: bottom center; + min-width: 10000%; + max-width: 10000%; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + border: 1px solid #B6C8D8; + border-top-style: none; + border-bottom-style: none; + color: #4B7CB4; + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #C0D7EF, stop: 1 #BFD7EE); +} +QTabWidget#QRibbonTabWidget QGroupBox { + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(218, 229, 242, 255), stop:0.2 rgba(218, 229, 242, 255), stop:0.201 rgba(198, 215, 236, 255), stop:1 rgba(213, 229, 243, 255)); + border: 1px solid #B6C8D8; + border-radius: 3px; +} +QWidget#QRibbonPanelFooter { + background-color: #c2d7f2; +} +QLabel#QRibbonPanelFooterLabel { + color: #4B7CB4; +} +QPushButton#sysIconLabel { + background-color: rgba(229, 229, 229, 0); +} +QPushButton#sysIconLabel:hover { + background-color: rgba(229, 229, 229, 0); +} +QPushButton#sysIconLabel:pressed { + background-color: rgba(202, 202, 202, 0); +} +QPushButton#sysIconLabel::menu-indicator{ + image:none; +} diff --git a/CbersUI/cbersui.qrc b/CbersUI/cbersui.qrc new file mode 100644 index 0000000..99a79aa --- /dev/null +++ b/CbersUI/cbersui.qrc @@ -0,0 +1,26 @@ + + + Resource/office2007_blue/office2007_blue.qss + Resource/office2007_blue/AppCaption/SysBtn_Close.png + Resource/office2007_blue/AppCaption/SysBtn_Maximize.png + Resource/office2007_blue/AppCaption/SysBtn_Minimize.png + Resource/office2007_blue/AppCaption/SysBtn_Restore.png + Resource/office2007_blue/AppCaption/Btn_HideElements.png + Resource/office2007_blue/AppCaption/Btn_ShowElements.png + Resource/office2007_black/AppCaption/Btn_HideElements.png + Resource/office2007_black/AppCaption/Btn_ShowElements.png + Resource/office2007_black/AppCaption/SysBtn_Close.png + Resource/office2007_black/AppCaption/SysBtn_Maximize.png + Resource/office2007_black/AppCaption/SysBtn_Minimize.png + Resource/office2007_black/AppCaption/SysBtn_Restore.png + Resource/office2007_black/office2007_black.qss + Resource/office2007_black/Black/caret-down_ffffff_14.png + Resource/office2007_black/Black/caret-right_ffffff_14.png + Resource/office2007_black/Black/check.png + Resource/office2007_black/Black/cross.svg + Resource/office2007_black/Black/down_arrow.png + Resource/office2007_black/Black/eye.svg + Resource/office2007_black/Black/eye-blocked.svg + Resource/office2007_black/Black/up_arrow.png + + diff --git a/CbersUI/cbersui_global.h b/CbersUI/cbersui_global.h new file mode 100644 index 0000000..ff0ff39 --- /dev/null +++ b/CbersUI/cbersui_global.h @@ -0,0 +1,22 @@ +#ifndef CBERSUI_GLOBAL_H +#define CBERSUI_GLOBAL_H + +#include + +#if defined(CBERSUI_LIBRARY) +# define CBERSUI_EXPORT Q_DECL_EXPORT +#else +# define CBERSUI_EXPORT Q_DECL_IMPORT +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#define BEGIN_NAMESPACE_CBERSUI namespace Cbers { namespace UI { +#define END_NAMESPACE_CBERSUI } } +#define USING_NAMESPACE_CBERSUI using namespace Cbers::UI; +#else +#define BEGIN_NAMESPACE_CBERSUI +#define END_NAMESPACE_CBERSUI +#define USING_NAMESPACE_CBERSUI +#endif + +#endif // CBERSUI_GLOBAL_H diff --git a/CbersUI/qribbonbar.cpp b/CbersUI/qribbonbar.cpp new file mode 100644 index 0000000..c67aa0d --- /dev/null +++ b/CbersUI/qribbonbar.cpp @@ -0,0 +1,235 @@ +#include "qribbonbar.h" +#include +#include +#include +#include +#include +#include "qribbonstylesheetmanager.h" +#include "qribbontabwidget.h" +#include "qtitlewidget.h" +USING_NAMESPACE_CBERSUI + +QRibbonBar::QRibbonBar(QWidget *parent) + : QWidget(parent), mParent(parent) +{ + setObjectName("QRibbonBar"); + QRibbonStyleSheetManager::instance()->applyStyleSheet("office2007_black"); + + QSize szButton(28, 28); + mShowElementsButton = new QPushButton(); + mShowElementsButton->setToolTip(tr("ShowElements")); + mShowElementsButton->setObjectName("Btn_ShowElements"); + mShowElementsButton->setFixedSize(szButton); + mShowElementsButton->hide(); + mHideElementsButton = new QPushButton(); + mHideElementsButton->setToolTip(tr("HideElements")); + mHideElementsButton->setObjectName("Btn_HideElements"); + mHideElementsButton->setFixedSize(szButton); + + mTabWidget = new QRibbonTabWidget(); + + //if( parent!=nullptr ) + // parent->installEventFilter(this); + + connect(mShowElementsButton, SIGNAL(clicked()), this, SLOT(showRibbonElements())); + connect(mHideElementsButton, SIGNAL(clicked()), this, SLOT(hideRibbonElements())); + + QTitleWidget* pTitleWidget = new QTitleWidget(this); + mTitleWidget = pTitleWidget; + installEventFilter(mTitleWidget); + pTitleWidget->addExtendedWidget(mShowElementsButton); + pTitleWidget->addExtendedWidget(mHideElementsButton); + + QHBoxLayout* tabLayout = new QHBoxLayout(); + tabLayout->addWidget(mTabWidget); + tabLayout->setSpacing(0); + tabLayout->setContentsMargins(0, 0, 0, 0); + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->addWidget(mTitleWidget, 0, Qt::AlignTop); + mainLayout->addLayout(tabLayout); + mainLayout->setSpacing(0); + mainLayout->setContentsMargins(1, 1, 1, 1); + setLayout(mainLayout); + + connect(mTabWidget, SIGNAL(currentChanged(int)) , this, SLOT(showRibbonElements())); + connect(mTabWidget, SIGNAL(tabBarClicked(int)) , this, SLOT(showRibbonElements())); + connect(mTabWidget, SIGNAL(toggled(bool)), this, SLOT(toggleRibbonElements(bool))); +} + + +QRibbonBar::~QRibbonBar() +{ + +} + +void QRibbonBar::toggleRibbonElements(bool show) +{ + if( show ) + { + mHideElementsButton->show(); + mShowElementsButton->hide(); + } + else + { + mHideElementsButton->hide(); + mShowElementsButton->show(); + } + + QRibbonTabWidget* pRibbonTabWidget = qobject_cast(mTabWidget); + if( pRibbonTabWidget!=nullptr ) + pRibbonTabWidget->showRibbonElements(show); +} + +void QRibbonBar::showRibbonElements() +{ + toggleRibbonElements(true); +} + +void QRibbonBar::hideRibbonElements() +{ + toggleRibbonElements(false); +} + +bool QRibbonBar::eventFilter(QObject *target, QEvent *e) +{ + return QWidget::eventFilter(target, e); +} + +QRibbonCategory* QRibbonBar::AddCategory(const QString& name, int nInsertAt) +{ + QRibbonCategory* pCategory = new QRibbonCategory(mTabWidget); + if( pCategory==nullptr ) + return nullptr; + + pCategory->setWindowTitle(name); + if( nInsertAt==-1 ) + { + mCategories.append(pCategory); + mTabWidget->addTab(pCategory, name); + } + else + { + nInsertAt = qMin(nInsertAt, mCategories.size()); + mCategories.insert(nInsertAt, pCategory); + mTabWidget->insertTab(nInsertAt, pCategory, name); + } + return pCategory; +} + +int QRibbonBar::GetCategoryCount() const +{ + return mCategories.size(); +} + +int QRibbonBar::GetVisibleCategoryCount() const +{ + return mTabWidget->count(); +} + +QRibbonCategory* QRibbonBar::GetCategory(int nIndex) const +{ + if( nIndex<0 || nIndex>=mCategories.size() ) + return nullptr; + + return mCategories.at(nIndex); +} + +int QRibbonBar::GetCategoryIndex(QRibbonCategory* pCategory) const +{ + return mCategories.indexOf(pCategory); +} + +void QRibbonBar::ShowCategory(int nIndex, bool bShow) +{ + if( nIndex<0 || nIndex>=mCategories.size() ) + return; + + QRibbonCategory* pCategory = mCategories.at(nIndex); + if( pCategory==nullptr ) + return; + + int nTabIndex = mTabWidget->indexOf(pCategory); + if( bShow && nTabIndex==-1 ) + { + bool bInsert = false; + for( int i=0; icount(); i++ ) + { + int index = mCategories.indexOf(qobject_cast(mTabWidget->widget(i))); + if( index>nIndex ) + { + mTabWidget->insertTab(i-1, pCategory, pCategory->windowTitle()); + bInsert = true; + break; + } + } + + if( !bInsert ) + mTabWidget->addTab(pCategory, pCategory->windowTitle()); + } + else if( !bShow && nTabIndex!=-1 ) + { + mTabWidget->removeTab(nTabIndex); + } +} + +bool QRibbonBar::RemoveCategory(int nIndex) +{ + if( nIndex<0 || nIndex>=mCategories.size() ) + return false; + + QRibbonCategory* pCategory = mCategories.at(nIndex); + int nTabIndex = mTabWidget->indexOf(pCategory); + if( nTabIndex>=0 ) + mTabWidget->removeTab(nTabIndex); + mCategories.removeAt(nIndex); + + pCategory->deleteLater(); + pCategory = nullptr; + return true; +} + +void QRibbonBar::RemoveAllCategories() +{ + for( int i=mTabWidget->count()-1; i>=0; i--) + mTabWidget->removeTab(i); + + for( int i=0; ideleteLater(); + } + mCategories.clear(); +} + +bool QRibbonBar::SetActiveCategory(QRibbonCategory* pCategory) +{ + if( pCategory==nullptr ) + return false; + + int nIndex = mTabWidget->indexOf(pCategory); + if( nIndex<0 ) + return false; + + mTabWidget->setCurrentIndex(nIndex); + return true; +} + +QRibbonCategory* QRibbonBar::GetActiveCategory() const +{ + QRibbonCategory* pCategory = qobject_cast(mTabWidget->currentWidget()); + return pCategory; +} + +QList QRibbonBar::FindCategoryByName(const QString& name) +{ + QList result; + for(int i=0; iwindowTitle().compare(name, Qt::CaseInsensitive)==0 ) + result.push_back(mCategories[i]); + } + + return result; +} diff --git a/CbersUI/qribbonbar.h b/CbersUI/qribbonbar.h new file mode 100644 index 0000000..5e4c598 --- /dev/null +++ b/CbersUI/qribbonbar.h @@ -0,0 +1,63 @@ +#ifndef QRIBBONBAR_H +#define QRIBBONBAR_H + +#include +#include +#include +#include +#include +#include +#include +#include "cbersui_global.h" +#include "qribboncategory.h" + +BEGIN_NAMESPACE_CBERSUI +class CBERSUI_EXPORT QRibbonBar : public QWidget +{ + Q_OBJECT +public: + explicit QRibbonBar(QWidget *parent = 0); + virtual ~QRibbonBar(); + +public: + QRibbonCategory* AddCategory(const QString& name, int nInsertAt = -1); + int GetCategoryCount() const; + int GetVisibleCategoryCount() const; + QRibbonCategory* GetCategory(int nIndex) const; + int GetCategoryIndex(QRibbonCategory* pCategory) const; + + void ShowCategory(int nIndex, bool bShow = true); + bool RemoveCategory(int nIndex); + void RemoveAllCategories(); + + virtual bool SetActiveCategory(QRibbonCategory* pCategory); + QRibbonCategory* GetActiveCategory() const; + + QList FindCategoryByName(const QString& name); + +signals: + +public slots: + void showRibbonElements(); + void hideRibbonElements(); + void toggleRibbonElements(bool show); + +protected: + bool eventFilter(QObject *target, QEvent *e); + +protected: + // TabWidget + QTabWidget* mTabWidget; + QList mCategories; + + QPushButton *mStylesButton; + QPushButton *mHelpButton; + + QPushButton *mShowElementsButton; + QPushButton *mHideElementsButton; + + QWidget* mParent; + QWidget* mTitleWidget; +}; +END_NAMESPACE_CBERSUI +#endif // QRIBBONBAR_H diff --git a/CbersUI/qribboncategory.cpp b/CbersUI/qribboncategory.cpp new file mode 100644 index 0000000..72ea3c2 --- /dev/null +++ b/CbersUI/qribboncategory.cpp @@ -0,0 +1,64 @@ +#include "qribboncategory.h" +#include +#include +USING_NAMESPACE_CBERSUI + +QRibbonCategory::QRibbonCategory(QWidget *parent) : QWidget(parent) +{ + setObjectName("QRibbonCategory"); + mHBoxLayout = new QHBoxLayout(); + mHBoxLayout->addStretch(1); + mHBoxLayout->setContentsMargins(0,0,0,0); + mHBoxLayout->setSpacing(2); + setLayout(mHBoxLayout); +} + +QRibbonPanel* QRibbonCategory::addPanel(const QString& name, int nInsertAt) +{ + QRibbonPanel* panel = new QRibbonPanel(name, this); + if( nInsertAt<0 ) + { + mHBoxLayout->insertWidget(mPanels.size(), panel); + mPanels.append(panel); + } + else + { + nInsertAt = qMin(nInsertAt, mPanels.size()); + mHBoxLayout->insertWidget(nInsertAt, panel); + mPanels.insert(nInsertAt, panel); + } + + return panel; +} + +bool QRibbonCategory::removePanel(int index, bool bDelete) +{ + if( index<0 || index>=mPanels.size() ) + return false; + + QRibbonPanel* panel = mPanels.at(index); + mHBoxLayout->removeWidget(panel); + mPanels.removeAt(index); + if( bDelete ) + panel->deleteLater(); + panel = nullptr; + return true; +} + +int QRibbonCategory::GetPanelIndex(QRibbonPanel* panel) +{ + return mPanels.indexOf(panel); +} + +int QRibbonCategory::GetPanelCount() const +{ + return mPanels.size(); +} + +QRibbonPanel* QRibbonCategory::GetPanel(int index) +{ + if( index<0 || index>=mPanels.size() ) + return nullptr; + + return mPanels.at(index); +} diff --git a/CbersUI/qribboncategory.h b/CbersUI/qribboncategory.h new file mode 100644 index 0000000..dc73535 --- /dev/null +++ b/CbersUI/qribboncategory.h @@ -0,0 +1,35 @@ +#ifndef QRIBBONCATEGORY_H +#define QRIBBONCATEGORY_H + +#include +#include +#include +#include +#include "cbersui_global.h" +#include "qribbonpanel.h" + +BEGIN_NAMESPACE_CBERSUI +class CBERSUI_EXPORT QRibbonCategory : public QWidget +{ + Q_OBJECT +public: + explicit QRibbonCategory(QWidget *parent = 0); + +public: + QRibbonPanel* addPanel(const QString& name, int nInsertAt = -1); + bool removePanel(int index, bool bDelete = true); + int GetPanelIndex(QRibbonPanel* panel); + + int GetPanelCount() const; + QRibbonPanel* GetPanel(int index); + +signals: + +public slots: + +protected: + QHBoxLayout* mHBoxLayout; + QList mPanels; +}; +END_NAMESPACE_CBERSUI +#endif // QRIBBONCATEGORY_H diff --git a/CbersUI/qribbonpanel.cpp b/CbersUI/qribbonpanel.cpp new file mode 100644 index 0000000..93d7010 --- /dev/null +++ b/CbersUI/qribbonpanel.cpp @@ -0,0 +1,95 @@ +#include "qribbonpanel.h" +#include +#include +#include +#include "qseparator.h" +USING_NAMESPACE_CBERSUI + +QRibbonPanel::QRibbonPanel(const QString& name, QWidget *parent) : QGroupBox(parent) +{ + setWindowTitle(name); + setObjectName("QRibbonPanelGroupBox"); + QVBoxLayout* groupBoxLayout = new QVBoxLayout(); + m_pWidgetLayout = new QHBoxLayout(); + m_pWidgetLayout->setSpacing(2); + m_pWidgetLayout->setContentsMargins(0,0,0,0); + groupBoxLayout->addLayout(m_pWidgetLayout); + + { + QWidget* footerWidget = new QWidget(); + footerWidget->setObjectName("QRibbonPanelFooter"); + QHBoxLayout *footerLayout = new QHBoxLayout(); + mTitle = new QLabel(name); + mTitle->setObjectName("QRibbonPanelFooterLabel"); + mTitle->setAlignment(Qt::AlignCenter); + footerLayout->addWidget(mTitle, 0, Qt::AlignCenter); + footerLayout->setContentsMargins(0,0,0,0); + footerWidget->setLayout(footerLayout); + groupBoxLayout->addWidget(footerWidget, 0, Qt::AlignBottom); + } + groupBoxLayout->setContentsMargins(2,0,2,0); + groupBoxLayout->setSpacing(2); + setLayout(groupBoxLayout); + //setMinimumWidth(32); +} + +void QRibbonPanel::Add(QWidget* pElem) +{ + if( pElem==nullptr ) + return; + + m_pWidgetLayout->addWidget(pElem); +} + +void QRibbonPanel::AddSeparator() +{ + QSeparator* pSeparator = new QSeparator(false); + m_pWidgetLayout->addWidget(pSeparator); +} + +bool QRibbonPanel::Insert(QWidget* pElem, int nIndex) +{ + if( pElem==nullptr ) + return false; + + if( nIndex<0 ) + nIndex = 0; + else if( nIndex>mElements.size() ) + nIndex = mElements.size(); + m_pWidgetLayout->insertWidget(nIndex, pElem); + return false; +} + +bool QRibbonPanel::InsertSeparator(int nIndex) +{ + if( nIndex<0 ) + nIndex = 0; + else if( nIndex>mElements.size() ) + nIndex = mElements.size(); + + QSeparator* pSeparator = new QSeparator(false); + m_pWidgetLayout->insertWidget(nIndex, pSeparator); + return true; +} + +int QRibbonPanel::GetCount() const +{ + return mElements.size(); +} + +bool QRibbonPanel::Remove(int nIndex) +{ + if( nIndex<0 || nIndex>mElements.size() ) + return false; + + m_pWidgetLayout->removeWidget(mElements[nIndex]); + mElements.removeAt(nIndex); + return true; +} + +void QRibbonPanel::RemoveAll() +{ + for(int i=0; iremoveWidget(mElements[i]); + mElements.clear(); +} diff --git a/CbersUI/qribbonpanel.h b/CbersUI/qribbonpanel.h new file mode 100644 index 0000000..586a3ac --- /dev/null +++ b/CbersUI/qribbonpanel.h @@ -0,0 +1,39 @@ +#ifndef QRIBBONPANEL_H +#define QRIBBONPANEL_H + +#include +#include +#include +#include +#include +#include +#include "cbersui_global.h" + +BEGIN_NAMESPACE_CBERSUI +class CBERSUI_EXPORT QRibbonPanel : public QGroupBox +{ + Q_OBJECT +public: + explicit QRibbonPanel(const QString& name, QWidget *parent = 0); + +public: + void Add(QWidget* pElem); + void AddSeparator(); + bool Insert(QWidget* pElem, int nIndex); + bool InsertSeparator(int nIndex); + + int GetCount() const; + bool Remove(int nIndex); + void RemoveAll(); + +signals: + +public slots: + +protected: + QHBoxLayout* m_pWidgetLayout; + QLabel* mTitle; + QList mElements; +}; +END_NAMESPACE_CBERSUI +#endif // QRIBBONPANEL_H diff --git a/CbersUI/qribbonstylesheetmanager.cpp b/CbersUI/qribbonstylesheetmanager.cpp new file mode 100644 index 0000000..5738c06 --- /dev/null +++ b/CbersUI/qribbonstylesheetmanager.cpp @@ -0,0 +1,77 @@ +#include "qribbonstylesheetmanager.h" +#include +#include +USING_NAMESPACE_CBERSUI + +QRibbonStyleSheetManager* QRibbonStyleSheetManager::sManager = nullptr; +QRibbonStyleSheetManager::QRibbonStyleSheetManager(QObject *parent) : QObject(parent) +{ + addStyleSheet("office2007_blue", loadStyleSheet(":/office2007/Resource/office2007_blue/office2007_blue.qss")); + addStyleSheet("office2007_black", loadStyleSheet(":/office2007/Resource/office2007_black/office2007_black.qss")); +} + +QRibbonStyleSheetManager* QRibbonStyleSheetManager::instance() +{ + if( sManager==nullptr ) + sManager = new QRibbonStyleSheetManager(); + return sManager; +} + +QString QRibbonStyleSheetManager::loadStyleSheet(const QString& url) +{ + QString styleSheet = ""; + QFile qss(url) ; + if(qss.open(QIODevice::ReadOnly)) + { + styleSheet = qss.readAll(); + qss.close() ; + } + + return styleSheet; +} + +int QRibbonStyleSheetManager::count() +{ + return mStyleSheets.count(); +} + +QString QRibbonStyleSheetManager::styleSheet(const QString& name) +{ + if( name.isEmpty() ) + return ""; + + return mStyleSheets.value(name.toLower()); +} + +bool QRibbonStyleSheetManager::addStyleSheet(const QString& name, const QString& styleSheet) +{ + if( name.isEmpty() || styleSheet.isEmpty() ) + return false; + + mStyleSheets.insert(name.toLower(), styleSheet); + return true; +} + +bool QRibbonStyleSheetManager::removeStyleSheet(const QString& name) +{ + return mStyleSheets.remove(name.toLower()); +} + +void QRibbonStyleSheetManager::clear() +{ + mStyleSheets.clear(); +} + +bool QRibbonStyleSheetManager::applyStyleSheet(const QString& name) +{ + QString style = styleSheet(name); + if( style.isEmpty() ) + return false; + + if( mOldStyleSheet.isEmpty() ) + mOldStyleSheet = qApp->styleSheet(); + + //style += mOldStyleSheet; + qApp->setStyleSheet(style); + return true; +} diff --git a/CbersUI/qribbonstylesheetmanager.h b/CbersUI/qribbonstylesheetmanager.h new file mode 100644 index 0000000..8220a08 --- /dev/null +++ b/CbersUI/qribbonstylesheetmanager.h @@ -0,0 +1,36 @@ +#ifndef QRIBBONSTYLESHEETMANAGER_H +#define QRIBBONSTYLESHEETMANAGER_H + +#include +#include +#include "cbersui_global.h" + +BEGIN_NAMESPACE_CBERSUI +class CBERSUI_EXPORT QRibbonStyleSheetManager : public QObject +{ + Q_OBJECT + +public: + static QRibbonStyleSheetManager* instance(); + int count(); + QString styleSheet(const QString& name); + bool addStyleSheet(const QString& name, const QString& styleSheet); + bool removeStyleSheet(const QString& name); + void clear(); + bool applyStyleSheet(const QString& name); + +protected: + explicit QRibbonStyleSheetManager(QObject *parent = 0); + QString loadStyleSheet(const QString& url); + +signals: + +public slots: + +private: + static QRibbonStyleSheetManager* sManager; + QMap mStyleSheets; + QString mOldStyleSheet; +}; +END_NAMESPACE_CBERSUI +#endif // QRIBBONSTYLESHEETMANAGER_H diff --git a/CbersUI/qribbontabwidget.cpp b/CbersUI/qribbontabwidget.cpp new file mode 100644 index 0000000..745347b --- /dev/null +++ b/CbersUI/qribbontabwidget.cpp @@ -0,0 +1,68 @@ +#include "qribbontabwidget.h" +#include +#include +USING_NAMESPACE_CBERSUI + +QRibbonTabWidget::QRibbonTabWidget(QWidget *parent) : QTabWidget(parent) +{ + mMinHeight = 32; +#ifdef Q_OS_WIN + mMaxHeight = 110; +#else + mMaxHeight = 120; +#endif + + if( tabBar()!=nullptr ) + mMinHeight = tabBar()->geometry().height() + 2; + + setObjectName("QRibbonTabWidget"); + setFixedHeight(mMaxHeight); + mOldSize = size(); +} + +void QRibbonTabWidget::mouseDoubleClickEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton ) + { + QRect tabBarRect; + if( tabBar()!=nullptr ) + { + tabBarRect.setTopLeft(tabBar()->mapToGlobal(tabBar()->geometry().topLeft())); + tabBarRect.setBottomRight(tabBar()->mapToGlobal(tabBar()->geometry().bottomRight())); + } + + QRect widgetRect; + if( currentWidget()!=nullptr ) + { + widgetRect.setTopLeft(currentWidget()->mapToGlobal(currentWidget()->geometry().topLeft())); + widgetRect.setBottomRight(currentWidget()->mapToGlobal(currentWidget()->geometry().bottomRight())); + } + + if( (!tabBarRect.isValid() || !tabBarRect.contains(event->globalPos())) + && (!widgetRect.isValid() || !widgetRect.contains(event->globalPos())) ) + { + showRibbonElements(!mShow); + emit toggled(mShow); + } + } +} + +void QRibbonTabWidget::showRibbonElements(bool show) +{ + if( mShow==show ) + return; + + mShow = show; + if( mShow ) + { + setFixedHeight(mMaxHeight); + resize(mOldSize); + } + else + { + mOldSize = size(); + QSize newSize(size().width(), mMinHeight); + setFixedHeight(mMinHeight); + resize(newSize); + } +} diff --git a/CbersUI/qribbontabwidget.h b/CbersUI/qribbontabwidget.h new file mode 100644 index 0000000..b430ff5 --- /dev/null +++ b/CbersUI/qribbontabwidget.h @@ -0,0 +1,32 @@ +#ifndef QRIBBONTABWIDGET_H +#define QRIBBONTABWIDGET_H + +#include +#include +#include +#include +#include "cbersui_global.h" + +BEGIN_NAMESPACE_CBERSUI +class CBERSUI_EXPORT QRibbonTabWidget : public QTabWidget +{ + Q_OBJECT +public: + explicit QRibbonTabWidget(QWidget *parent = 0); + + void showRibbonElements(bool show); + +protected: + void mouseDoubleClickEvent(QMouseEvent *event); + +signals: + void toggled(bool); + +protected: + bool mShow; + QSize mOldSize; + int mMaxHeight; + int mMinHeight; +}; +END_NAMESPACE_CBERSUI +#endif // QRIBBONTABWIDGET_H diff --git a/CbersUI/qseparator.cpp b/CbersUI/qseparator.cpp new file mode 100644 index 0000000..c97c867 --- /dev/null +++ b/CbersUI/qseparator.cpp @@ -0,0 +1,8 @@ +#include "qseparator.h" +USING_NAMESPACE_CBERSUI + +QSeparator::QSeparator(bool bVLine, QWidget *parent) : QFrame(parent) +{ + setFrameShape(bVLine ? QFrame::VLine : QFrame::HLine); + setFrameShadow(QFrame::Sunken); +} diff --git a/CbersUI/qseparator.h b/CbersUI/qseparator.h new file mode 100644 index 0000000..2c6e19a --- /dev/null +++ b/CbersUI/qseparator.h @@ -0,0 +1,20 @@ +#ifndef QSEPARATOR_H +#define QSEPARATOR_H + +#include +#include "cbersui_global.h" +BEGIN_NAMESPACE_CBERSUI + +class CBERSUI_EXPORT QSeparator : public QFrame +{ + Q_OBJECT +public: + explicit QSeparator(bool bVLine = false, QWidget *parent = 0); + +signals: + +public slots: +}; + +END_NAMESPACE_CBERSUI +#endif // QSEPARATOR_H diff --git a/CbersUI/qtitlewidget.cpp b/CbersUI/qtitlewidget.cpp new file mode 100644 index 0000000..7a46272 --- /dev/null +++ b/CbersUI/qtitlewidget.cpp @@ -0,0 +1,366 @@ +#include "qtitlewidget.h" +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN +#pragma comment(lib, "user32.lib") +#include +#endif +USING_NAMESPACE_CBERSUI + +QTitleWidget::QTitleWidget(QWidget *parent) : QWidget(parent) +{ + setObjectName("QRibbonTitleWidget"); + setFixedHeight(30); + m_bPressed = false; + + m_pIconLabel = new QPushButton(this); + m_pIconLabel->setObjectName("sysIconLabel"); + //m_pIconLabel->setStyleSheet("QPushButton {background-color: rgba(229, 229, 229, 0);} QPushButton:hover {background-color: rgba(229, 229, 229, 0);} QPushButton:pressed {background-color: rgba(202, 202, 202, 0);} QPushButton::menu-indicator{image:none;}"); + m_pTitleLabel = new QLabel(this); + m_pMinimizeButton = new QPushButton(this); + m_pMaximizeButton = new QPushButton(this); + m_pRestoreButton = new QPushButton(this); + m_pCloseButton = new QPushButton(this); + + QWidget *pWindow = this->window(); + if (pWindow!=nullptr && pWindow->isTopLevel()) + { + m_pTitleLabel->setText(pWindow->windowTitle()); + QIcon icon = pWindow->windowIcon(); + m_pIconLabel->setIcon(icon);//setPixmap(icon.pixmap(m_pIconLabel->size())); + } + + m_pRestoreButton->hide(); + m_pRestoreButton->setDisabled(true); + + QSize szIcon(20, 20); + m_pIconLabel->setFixedSize(szIcon); + //m_pIconLabel->setScaledContents(true); + + m_pTitleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + QSize szButton(28, 28); + m_pMinimizeButton->setFixedSize(szButton); + m_pMaximizeButton->setFixedSize(szButton); + m_pRestoreButton->setFixedSize(szButton); + m_pCloseButton->setFixedSize(szButton); + + m_pTitleLabel->setObjectName("sysTitle"); + m_pMinimizeButton->setObjectName("SysBtn_Minimize"); + m_pMaximizeButton->setObjectName("SysBtn_Maximize"); + m_pRestoreButton->setObjectName("SysBtn_Restore"); + m_pCloseButton->setObjectName("SysBtn_Close"); + + m_pMinimizeButton->setToolTip(tr("Minimize")); + m_pMaximizeButton->setToolTip(tr("Maximize")); + m_pRestoreButton->setToolTip(tr("Restore")); + m_pCloseButton->setToolTip(tr("Close")); + + QMenu* mainMenu = new QMenu(this); + QAction* restoreAction = new QAction(m_pRestoreButton->icon(), tr("Restore"), nullptr); + connect(restoreAction, SIGNAL(triggered()), m_pRestoreButton, SLOT(click())); + mainMenu->addAction(restoreAction); + + mMoveAction = new QAction(tr("Move"), nullptr); + connect(mMoveAction, SIGNAL(triggered()), this, SLOT(onMove())); + mainMenu->addAction(mMoveAction); + + QAction* minimizeAction = new QAction(m_pRestoreButton->icon(), tr("Minimize"), nullptr); + connect(minimizeAction, SIGNAL(triggered()), m_pMinimizeButton, SLOT(click())); + mainMenu->addAction(minimizeAction); + + QAction* maximizeAction = new QAction(m_pMaximizeButton->icon(), tr("Maximize"), nullptr); + connect(maximizeAction, SIGNAL(triggered()), m_pMaximizeButton, SLOT(click())); + mainMenu->addAction(maximizeAction); + + mainMenu->addSeparator(); + + QAction* closeAction = new QAction(m_pCloseButton->icon(), tr("Close"), nullptr); + connect(closeAction, SIGNAL(triggered()), m_pCloseButton, SLOT(click())); + mainMenu->addAction(closeAction); + + m_pIconLabel->setMenu(mainMenu); + + + QHBoxLayout *pLayout = new QHBoxLayout(nullptr); + pLayout->addWidget(m_pIconLabel); + m_pWidgetLayout = new QHBoxLayout(nullptr); + pLayout->addLayout(m_pWidgetLayout); + pLayout->addSpacing(5); + pLayout->addWidget(m_pTitleLabel); + m_pExtendedLayout = new QHBoxLayout(nullptr); + pLayout->addLayout(m_pExtendedLayout); + pLayout->addWidget(m_pMinimizeButton); + pLayout->addWidget(m_pMaximizeButton); + pLayout->addWidget(m_pRestoreButton); + pLayout->addWidget(m_pCloseButton); + pLayout->setSpacing(0); + pLayout->setContentsMargins(5, 0, 5, 0); + + setLayout(pLayout); + + connect(m_pMinimizeButton, SIGNAL(clicked(bool)), this, SLOT(onMinimized())); + connect(m_pMaximizeButton, SIGNAL(clicked(bool)), this, SLOT(onMaximized())); + connect(m_pRestoreButton, SIGNAL(clicked(bool)), this, SLOT(onRestore())); + connect(m_pCloseButton, SIGNAL(clicked(bool)), this, SLOT(onClose())); +} + +QTitleWidget::~QTitleWidget() +{ + +} + +void QTitleWidget::mouseDoubleClickEvent(QMouseEvent *event) +{ + Q_UNUSED(event); + + //emit m_pMaximizeButton->clicked(); + QWidget *pWindow = this->window(); + if (pWindow->isTopLevel()) + { + if( pWindow->isMaximized() ) + pWindow->showNormal(); + else + pWindow->showMaximized(); + } +} + +void QTitleWidget::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + { + m_bPressed = true; + m_point = event->pos(); + } + /* +#ifdef Q_OS_WIN + if (ReleaseCapture()) + { + QWidget *pWindow = this->window(); + if (pWindow->isTopLevel()) + { + //pWindow->setCursor(QCursor(Qt::ArrowCursor)); + //if( pWindow->isMaximized() ) + // pWindow->overrideWindowState(Qt::WindowNoState); + SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0); + } + } + event->ignore(); +#else +#endif + */ +} + +void QTitleWidget::mouseReleaseEvent(QMouseEvent *event) +{ + Q_UNUSED(event); + m_bPressed = false; +} + +void QTitleWidget::mouseMoveEvent(QMouseEvent *event) +{ + if (m_bPressed && event->pos()!=m_point) + { + QWidget *pWindow = this->window(); + if (pWindow->isTopLevel()) + { + if( pWindow->isMaximized() ) + { + QPoint oldTopLeft = this->mapToGlobal(this->geometry().topLeft()); + QPoint oldBottomRight = this->mapToGlobal(this->geometry().bottomRight()); + if( m_pWidgetLayout!=nullptr ) + oldTopLeft.setX(this->mapToGlobal(m_pWidgetLayout->contentsRect().bottomRight()).x()); + if( m_pExtendedLayout!=nullptr ) + oldBottomRight.setX(this->mapToGlobal(m_pExtendedLayout->contentsRect().topLeft()).x()); + bool inTitleLabel = false; + if( m_pTitleLabel!=nullptr && event->pos().x()<=(m_pTitleLabel->mapToGlobal(m_pTitleLabel->geometry().topLeft()).x() + m_pTitleLabel->sizeHint().width())) + inTitleLabel = true; + bool inExtendedLayout = false; + if( m_pExtendedLayout!=nullptr && event->pos().x()>=(this->mapToGlobal(m_pExtendedLayout->contentsRect().topLeft()).x())) + inExtendedLayout = true; + pWindow->showNormal(); + if(m_normalGeometry.isEmpty()) + { + QRect rect = pWindow->geometry(); + rect.setWidth(rect.width()/2); + rect.setHeight(rect.height()/2); + pWindow->setGeometry(rect); + } + else + pWindow->restoreGeometry(m_normalGeometry); + QPoint newTopLeft = this->mapToGlobal(this->geometry().topLeft()); + QPoint newBottomRight = this->mapToGlobal(this->geometry().bottomRight()); + if( m_pWidgetLayout!=nullptr ) + newTopLeft.setX(this->mapToGlobal(m_pWidgetLayout->contentsRect().bottomRight()).x()); + if( m_pExtendedLayout!=nullptr ) + newBottomRight.setX(this->mapToGlobal(m_pExtendedLayout->contentsRect().topLeft()).x()); + + QPoint newPoint(newTopLeft.x() + (event->pos().x() - oldTopLeft.x()) * (newBottomRight.x() - newTopLeft.x()) / (oldBottomRight.x() - oldTopLeft.x()), + newTopLeft.y() + (event->pos().y() - oldTopLeft.y()) * (newBottomRight.y() - newTopLeft.y()) / (oldBottomRight.y() - oldTopLeft.y())); + if( inTitleLabel && (newBottomRight.x() - newTopLeft.x() > event->pos().x() - oldTopLeft.x()) ) + newPoint.setX(newTopLeft.x() + (event->pos().x() - oldTopLeft.x())); + else if( inExtendedLayout && (newBottomRight.x() - newTopLeft.x() > oldBottomRight.x() - event->pos().x()) ) + newPoint.setX(newBottomRight.x() - (oldBottomRight.x() - event->pos().x())); + + if( m_pExtendedLayout!=nullptr ) + { + newPoint.setX(qMin(newPoint.x(), this->mapToGlobal(m_pExtendedLayout->contentsRect().topLeft()).x())); + } + + if( m_pWidgetLayout!=nullptr ) + newPoint.setX(qMax(newPoint.x(), this->mapToGlobal(m_pWidgetLayout->contentsRect().bottomRight()).x())); + + m_point = newPoint; + pWindow->move(event->pos() - newPoint + pWindow->pos()); + } + else + pWindow->move(event->pos() - m_point + pWindow->pos()); + } + } +} + +bool QTitleWidget::eventFilter(QObject *obj, QEvent *event) +{ + switch (event->type()) + { + case QEvent::WindowTitleChange: + { + QWidget *pWidget = qobject_cast(obj); + if (pWidget) + { + m_pTitleLabel->setText(pWidget->windowTitle()); + return true; + } + } + case QEvent::WindowIconChange: + { + QWidget *pWidget = qobject_cast(obj); + if (pWidget) + { + QIcon icon = pWidget->windowIcon(); + m_pIconLabel->setIcon(icon);//setPixmap(icon.pixmap(m_pIconLabel->size())); + return true; + } + } + case QEvent::WindowStateChange: + case QEvent::Resize: + { + updateMaximize(); + return true; + } + } + return QWidget::eventFilter(obj, event); +} + +void QTitleWidget::onMove() +{ + QPoint center = this->mapToGlobal(this->geometry().center()); + QCursor::setPos(center); + m_bPressed = true; + m_point = center; + /* +#ifdef Q_OS_WIN + if (ReleaseCapture()) + { + QWidget *pWindow = this->window(); + if (pWindow->isTopLevel()) + { + if( pWindow->isMaximized() ) + pWindow->overrideWindowState(Qt::WindowNoState); + + QPoint center = this->mapToGlobal(this->geometry().center()); + QCursor::setPos(center); + //pWindow->setCursor(QCursor(Qt::SizeAllCursor)); + //this->cursor().setShape(Qt::SizeAllCursor); + SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0); + } + } +#else +#endif + */ +} + +void QTitleWidget::onMinimized() +{ + QWidget *pWindow = this->window(); + if (pWindow->isTopLevel()) + pWindow->showMinimized(); +} + +void QTitleWidget::onMaximized() +{ + QWidget *pWindow = this->window(); + if (pWindow->isTopLevel()) + { + pWindow->showMaximized(); + //m_pRestoreButton->show(); + //m_pMaximizeButton->hide(); + } +} + +void QTitleWidget::onRestore() +{ + QWidget *pWindow = this->window(); + if (pWindow->isTopLevel()) + { + pWindow->showNormal(); + //m_pRestoreButton->hide(); + //m_pMaximizeButton->show(); + } +} + +void QTitleWidget::onClose() +{ + QWidget *pWindow = this->window(); + if (pWindow->isTopLevel()) + pWindow->close(); +} + +void QTitleWidget::updateMaximize() +{ + QWidget *pWindow = this->window(); + if (pWindow->isTopLevel()) + { + bool bMaximize = pWindow->isMaximized(); + if (bMaximize) + { + m_pRestoreButton->show(); + m_pRestoreButton->setDisabled(false); + m_pMaximizeButton->hide(); + m_pMaximizeButton->setDisabled(true); + mMoveAction->setEnabled(false); + } + else + { + m_pRestoreButton->hide(); + m_pRestoreButton->setDisabled(true); + m_pMaximizeButton->show(); + m_pMaximizeButton->setDisabled(false); + mMoveAction->setEnabled(true); + m_normalGeometry = pWindow->saveGeometry(); + } + } +} + +bool QTitleWidget::addWidget(QWidget* widget, int index) +{ + if( m_pWidgetLayout==nullptr || widget==nullptr ) + return false; + + m_pWidgetLayout->addWidget(widget); + return true; +} + +bool QTitleWidget::addExtendedWidget(QWidget* widget, int index) +{ + if( m_pExtendedLayout==nullptr || widget==nullptr ) + return false; + + m_pExtendedLayout->addWidget(widget); + return true; +} diff --git a/CbersUI/qtitlewidget.h b/CbersUI/qtitlewidget.h new file mode 100644 index 0000000..0d01270 --- /dev/null +++ b/CbersUI/qtitlewidget.h @@ -0,0 +1,61 @@ +#ifndef QTITLEWIDGET_H +#define QTITLEWIDGET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cbersui_global.h" + +BEGIN_NAMESPACE_CBERSUI +class CBERSUI_EXPORT QTitleWidget : public QWidget +{ + Q_OBJECT +public: + explicit QTitleWidget(QWidget *parent = 0); + ~QTitleWidget(); + +public: + bool addWidget(QWidget* widget, int index = -1); + bool addExtendedWidget(QWidget* widget, int index = -1); + +protected: + virtual void mouseDoubleClickEvent(QMouseEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual bool eventFilter(QObject *obj, QEvent *event); + +public slots: + void onMinimized(); + void onMaximized(); + void onRestore(); + void onClose(); + void onMove(); + +private: + void updateMaximize(); + +protected: + QPushButton *m_pIconLabel; + QLabel *m_pTitleLabel; + QPushButton *m_pMinimizeButton; + QPushButton *m_pMaximizeButton; + QPushButton *m_pRestoreButton; + QPushButton *m_pCloseButton; + QAction* mMoveAction; + + QHBoxLayout* m_pWidgetLayout; + QHBoxLayout* m_pExtendedLayout; + +private: + bool m_bPressed; + QPoint m_point; + QByteArray m_normalGeometry; +}; +END_NAMESPACE_CBERSUI +#endif // QTITLEWIDGET_H diff --git a/README.md b/README.md deleted file mode 100644 index 781c3b7..0000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# CbersUI -QT Ribbon - -特别感谢 一去丶二三里 http://blog.csdn.net/liang19890820, 博主文章中关于QT的讲解非常清楚 diff --git a/plugins/PluginDemo/CommandPlugin.png b/plugins/PluginDemo/CommandPlugin.png new file mode 100644 index 0000000..0566f1d Binary files /dev/null and b/plugins/PluginDemo/CommandPlugin.png differ diff --git a/plugins/PluginDemo/DockWidgetPlugin.png b/plugins/PluginDemo/DockWidgetPlugin.png new file mode 100644 index 0000000..0566f1d Binary files /dev/null and b/plugins/PluginDemo/DockWidgetPlugin.png differ diff --git a/plugins/PluginDemo/PluginDemo.pro b/plugins/PluginDemo/PluginDemo.pro new file mode 100644 index 0000000..ad39e48 --- /dev/null +++ b/plugins/PluginDemo/PluginDemo.pro @@ -0,0 +1,42 @@ +TEMPLATE = lib +TARGET = PluginDemo +QT += core + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +# Input +SOURCES += module.cpp \ + viewplugin.cpp \ + dockwidgetplugin.cpp \ + commandplugin.cpp \ + toolplugin.cpp + +HEADERS += \ + viewplugin.h \ + dockwidgetplugin.h \ + commandplugin.h \ + toolplugin.h +PROJECT_PATH = $$PWD +SDK_PATH = $$PROJECT_PATH/../../ +#TRANSLATION_LANGS = zh_CN +include( ../../include/pluginconfig.pri ) +QMAKE_POST_LINK += $$copyToDir($$PROJECT_PATH/*.png, $$DESTDIR/../Skins/) + +DISTFILES += \ + ViewPlugin.png \ + DockWidgetPlugin.png \ + CommandPlugin.png \ + ToolPlugin.png + +FORMS += \ No newline at end of file diff --git a/plugins/PluginDemo/ToolPlugin.png b/plugins/PluginDemo/ToolPlugin.png new file mode 100644 index 0000000..0566f1d Binary files /dev/null and b/plugins/PluginDemo/ToolPlugin.png differ diff --git a/plugins/PluginDemo/ViewPlugin.png b/plugins/PluginDemo/ViewPlugin.png new file mode 100644 index 0000000..0566f1d Binary files /dev/null and b/plugins/PluginDemo/ViewPlugin.png differ diff --git a/plugins/PluginDemo/commandplugin.cpp b/plugins/PluginDemo/commandplugin.cpp new file mode 100644 index 0000000..e835b90 --- /dev/null +++ b/plugins/PluginDemo/commandplugin.cpp @@ -0,0 +1,136 @@ +#include "commandplugin.h" +#include +#include +#include +#include +#include + +CommandPlugin::CommandPlugin(QObject *parent) : QObject(parent) +{ + Name(QStringLiteral("CommandPlugin")); + Caption(QStringLiteral("Buttons")); + Category(QStringLiteral("Plugins")); + Tooltip(QStringLiteral("CommandPlugin")); + Description(QStringLiteral("CommandPlugin")); + BitmapName(QStringLiteral("CommandPlugin")); + + + mToolButton = Q_NULLPTR; + mDefaultIcon = true; + +} + +CommandPlugin::~CommandPlugin() +{ + UnInitialize(); +} + +// IUIPlugin +bool CommandPlugin::Initialize() +{ + mToolButton = new QToolButton(); + mToolButton->setText(Name()); + mToolButton->setToolTip(Tooltip()); + mToolButton->setIconSize(QSize(32, 32)); + mToolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + mToolButton->setAutoRaise(true); + mToolButton->setMouseTracking(true); + QString strBitmapName = BitmapName(); + QIcon icon; + if( !strBitmapName.isEmpty() ) + { + strBitmapName = QString("%1/Skins/%2.png").arg(QApplication::applicationDirPath()).arg(strBitmapName); + QFileInfo fileInfo(strBitmapName); + if( !fileInfo.exists() ) + { + strBitmapName = QString("%1/Skins/default.png").arg(QApplication::applicationDirPath()); + fileInfo.setFile(strBitmapName); + } + else + mDefaultIcon = false; + + if( fileInfo.exists() ) + icon.addFile(strBitmapName); + } + + if( !icon.isNull() ) + { + mToolButton->setIcon(icon); + } + + mToolButton->setCheckable(false); + this->connect(mToolButton, SIGNAL(clicked()), this, SLOT(clicked())); + + // Only Support appoint Events + //supportsEvent("EventKey"); + registerHandlers(); + return true; +} + +bool CommandPlugin::UnInitialize() +{ + if( mToolButton!=Q_NULLPTR ) + delete mToolButton; + mToolButton = Q_NULLPTR; + + unregisterHandlers(); + return true; +} + +bool CommandPlugin::SetBuddy(x3::IObject* val) +{ + if( m_spBuddy==val ) + return true; + + m_spBuddy = val; + if( !m_spBuddy.valid() ) + { + mToolButton->setEnabled(false); + return false; + } + + mToolButton->setEnabled(true); + + return true; +} + +bool CommandPlugin::readConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ) +{ + if( !((IUIPlugin*)this)->readConfig(node, document, errorMessage) ) + return false; + + return true; +} + +bool CommandPlugin::writeConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ) +{ + if( !((IUIPlugin*)this)->writeConfig(node, document, errorMessage) ) + return false; + + return true; +} + +// IUICommand +QWidget* CommandPlugin::getButtonWidget() +{ + return mToolButton; +} + +QWidget* CommandPlugin::getWndWidget() +{ + return Q_NULLPTR; +} + +// IAnythingEventObserver +bool CommandPlugin::OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam) +{ + //if( _stricmp(eventKey.c_str(), "EventKey")==0 ) + //{ + //} + return true; +} + +void CommandPlugin::clicked() +{ + QMessageBox::information(Q_NULLPTR, "CommandPlugin", "CommandPlugin clicked"); +} diff --git a/plugins/PluginDemo/commandplugin.h b/plugins/PluginDemo/commandplugin.h new file mode 100644 index 0000000..5dc6c6f --- /dev/null +++ b/plugins/PluginDemo/commandplugin.h @@ -0,0 +1,51 @@ +#ifndef COMMANDPLUGIN_H +#define COMMANDPLUGIN_H +#include +#include + +#include "UIPluginsEvents.h" +#include "UIPlugins.h" +USING_NAMESPACE_CBERSPLUGINS + +const char* const clsidCommandPlugin = "clsidCommandPlugin"; +class CommandPlugin : public QObject + , public IUIPlugin + , public IUICommand + , public IAnythingEventObserver +{ + Q_OBJECT + X3BEGIN_CLASS_DECLARE(CommandPlugin, clsidCommandPlugin) + X3DEFINE_INTERFACE_ENTRY(IUIPlugin) + X3DEFINE_INTERFACE_ENTRY(IUICommand) + X3END_CLASS_DECLARE() + + public: + explicit CommandPlugin(QObject *parent = 0); + ~CommandPlugin(); + +public: + // IUIPlugin + virtual bool Initialize(); + virtual bool UnInitialize(); + virtual bool SetBuddy(x3::IObject* val); + virtual bool readConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ); + virtual bool writeConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ); + + // IUICommand + virtual QWidget* getButtonWidget(); + virtual QWidget* getWndWidget(); + + // IAnythingEventObserver + virtual bool OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam); + +signals: + +public slots: + void clicked(); + +protected: + QToolButton* mToolButton; + bool mDefaultIcon; +}; + +#endif // COMMANDPLUGIN_H \ No newline at end of file diff --git a/plugins/PluginDemo/dockwidgetplugin.cpp b/plugins/PluginDemo/dockwidgetplugin.cpp new file mode 100644 index 0000000..d3a9672 --- /dev/null +++ b/plugins/PluginDemo/dockwidgetplugin.cpp @@ -0,0 +1,149 @@ +#include "dockwidgetplugin.h" +#include "ui_dockwidgetplugin.h" +#include +#include +#include +#include + +DockWidgetPlugin::DockWidgetPlugin(QWidget *parent) : QDockWidget(parent) +{ + Name(QStringLiteral("DockWidgetPlugin")); + Caption(QStringLiteral("View")); + Category(QStringLiteral("Plugins")); + Tooltip(QStringLiteral("DockWidgetPlugin")); + Description(QStringLiteral("DockWidgetPlugin")); + BitmapName(QStringLiteral("DockWidgetPlugin")); + + setWindowTitle(Name()); + + mToolButton = Q_NULLPTR; + mDefaultIcon = true; + +} + +DockWidgetPlugin::~DockWidgetPlugin() +{ + UnInitialize(); +} + +// IUIPlugin +bool DockWidgetPlugin::Initialize() +{ + mToolButton = new QToolButton(); + mToolButton->setText(Name()); + mToolButton->setToolTip(Tooltip()); + mToolButton->setIconSize(QSize(32, 32)); + mToolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + mToolButton->setAutoRaise(true); + mToolButton->setMouseTracking(true); + QString strBitmapName = BitmapName(); + QIcon icon; + if( !strBitmapName.isEmpty() ) + { + strBitmapName = QString("%1/Skins/%2.png").arg(QApplication::applicationDirPath()).arg(strBitmapName); + QFileInfo fileInfo(strBitmapName); + if( !fileInfo.exists() ) + { + strBitmapName = QString("%1/Skins/default.png").arg(QApplication::applicationDirPath()); + fileInfo.setFile(strBitmapName); + } + else + mDefaultIcon = false; + + if( fileInfo.exists() ) + icon.addFile(strBitmapName); + } + + if( !icon.isNull() ) + { + mToolButton->setIcon(icon); + setWindowIcon(icon); + } + + mToolButton->setCheckable(true); + QAction* actionDockWidget = toggleViewAction(); + actionDockWidget->setIcon(icon); + actionDockWidget->setText(Name()); + actionDockWidget->setToolTip(Tooltip()); + mToolButton->setDefaultAction(actionDockWidget); + this->connect(mToolButton, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); + + // Only Support appoint Events + //supportsEvent("EventKey"); + registerHandlers(); + return true; +} + +bool DockWidgetPlugin::UnInitialize() +{ + if( mToolButton!=Q_NULLPTR ) + delete mToolButton; + mToolButton = Q_NULLPTR; + + unregisterHandlers(); + hide(); + return true; +} + +bool DockWidgetPlugin::SetBuddy(x3::IObject* val) +{ + if( m_spBuddy==val ) + return true; + + m_spBuddy = val; + if( !m_spBuddy.valid() ) + { + mToolButton->setEnabled(false); + return false; + } + + mToolButton->setEnabled(true); + + return true; +} + +bool DockWidgetPlugin::readConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ) +{ + if( !((IUIPlugin*)this)->readConfig(node, document, errorMessage) ) + return false; + + return true; +} + +bool DockWidgetPlugin::writeConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ) +{ + if( !((IUIPlugin*)this)->writeConfig(node, document, errorMessage) ) + return false; + + return true; +} + +// IUICommand +QWidget* DockWidgetPlugin::getButtonWidget() +{ + return mToolButton; +} + +QWidget* DockWidgetPlugin::getWndWidget() +{ + show(); + return this; +} + +// IAnythingEventObserver +bool DockWidgetPlugin::OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam) +{ + //if( _stricmp(eventKey.c_str(), "EventKey")==0 ) + //{ + //} + return true; +} + +void DockWidgetPlugin::toggled(bool checked) +{ + if( checked ) + { + setVisible(true); + raise(); + } +} diff --git a/plugins/PluginDemo/dockwidgetplugin.h b/plugins/PluginDemo/dockwidgetplugin.h new file mode 100644 index 0000000..5bb5241 --- /dev/null +++ b/plugins/PluginDemo/dockwidgetplugin.h @@ -0,0 +1,51 @@ +#ifndef DOCKWIDGETPLUGIN_H +#define DOCKWIDGETPLUGIN_H +#include +#include + +#include "UIPluginsEvents.h" +#include "UIPlugins.h" +USING_NAMESPACE_CBERSPLUGINS + +const char* const clsidDockWidgetPlugin = "clsidDockWidgetPlugin"; +class DockWidgetPlugin : public QDockWidget + , public IUIPlugin + , public IUICommand + , public IAnythingEventObserver +{ + Q_OBJECT + X3BEGIN_CLASS_DECLARE(DockWidgetPlugin, clsidDockWidgetPlugin) + X3DEFINE_INTERFACE_ENTRY(IUIPlugin) + X3DEFINE_INTERFACE_ENTRY(IUICommand) + X3END_CLASS_DECLARE() + + public: + explicit DockWidgetPlugin(QWidget *parent = 0); + ~DockWidgetPlugin(); + +public: + // IUIPlugin + virtual bool Initialize(); + virtual bool UnInitialize(); + virtual bool SetBuddy(x3::IObject* val); + virtual bool readConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ); + virtual bool writeConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ); + + // IUICommand + virtual QWidget* getButtonWidget(); + virtual QWidget* getWndWidget(); + + // IAnythingEventObserver + virtual bool OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam); + +signals: + +public slots: + void toggled(bool checked); + +protected: + QToolButton* mToolButton; + bool mDefaultIcon; +}; + +#endif // DOCKWIDGETPLUGIN_H diff --git a/plugins/PluginDemo/module.cpp b/plugins/PluginDemo/module.cpp new file mode 100644 index 0000000..2569f09 --- /dev/null +++ b/plugins/PluginDemo/module.cpp @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include "module/plugininc.h" +#include "module/pluginimpl.h" +#include "module/modulemacro.h" +#include "observer/observerimpl.h" +#include "viewplugin.h" +#include "dockwidgetplugin.h" +#include "commandplugin.h" +#include "toolplugin.h" + +XBEGIN_DEFINE_MODULE() + XDEFINE_CLASSMAP_ENTRY(ViewPlugin) + XDEFINE_CLASSMAP_ENTRY(DockWidgetPlugin) + XDEFINE_CLASSMAP_ENTRY(CommandPlugin) + XDEFINE_CLASSMAP_ENTRY(ToolPlugin) +XEND_DEFINE_MODULE_DLL() + +QTranslator gTranslator; +OUTAPI bool x3InitializePlugin() +{ + ////////////////////////////////////////////////////////////// + // Load Translator + QSettings mySettings; + QString i18nPath = QApplication::applicationDirPath() + QDir::separator() + "i18n"; + QString myUserLocale = mySettings.value( "locale/userLocale", "" ).toString(); + bool myLocaleOverrideFlag = mySettings.value( "locale/overrideFlag", false ).toBool(); + QString myTranslationCode; + if ( !myTranslationCode.isNull() && !myTranslationCode.isEmpty() ) + { + mySettings.setValue( "locale/userLocale", myTranslationCode ); + } + else + { + if ( !myLocaleOverrideFlag || myUserLocale.isEmpty() ) + { + myTranslationCode = QLocale::system().name(); + mySettings.setValue( "locale/userLocale", myTranslationCode ); + } + else + { + myTranslationCode = myUserLocale; + } + } + + if ( myTranslationCode != "C" ) + { + if ( gTranslator.load( QString( "PluginDemo_" ) + myTranslationCode, i18nPath ) ) + { + QApplication::installTranslator( &gTranslator ); + } + else + { + qWarning( "loading of PluginDemo translation failed [%s]", QString( "%1/PluginDemo_%2" ).arg( i18nPath ).arg( myTranslationCode ).toLocal8Bit().constData() ); + } + } + ////////////////////////////////////////////////////////////// + return true; +} + +OUTAPI void x3UninitializePlugin() +{ + if( !gTranslator.isEmpty() ) + { + QApplication::removeTranslator( &gTranslator ); + } +} diff --git a/plugins/PluginDemo/toolplugin.cpp b/plugins/PluginDemo/toolplugin.cpp new file mode 100644 index 0000000..7324aff --- /dev/null +++ b/plugins/PluginDemo/toolplugin.cpp @@ -0,0 +1,139 @@ +#include "toolplugin.h" +#include +#include +#include +#include +#include + +ToolPlugin::ToolPlugin(QObject *parent) : QObject(parent) +{ + Name(QStringLiteral("ToolPlugin")); + Caption(QStringLiteral("Buttons")); + Category(QStringLiteral("Plugins")); + Tooltip(QStringLiteral("ToolPlugin")); + Description(QStringLiteral("ToolPlugin")); + BitmapName(QStringLiteral("ToolPlugin")); + + + mToolButton = Q_NULLPTR; + mDefaultIcon = true; + +} + +ToolPlugin::~ToolPlugin() +{ + UnInitialize(); +} + +// IUIPlugin +bool ToolPlugin::Initialize() +{ + mToolButton = new QToolButton(); + mToolButton->setText(Name()); + mToolButton->setToolTip(Tooltip()); + mToolButton->setIconSize(QSize(32, 32)); + mToolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + mToolButton->setAutoRaise(true); + mToolButton->setMouseTracking(true); + QString strBitmapName = BitmapName(); + QIcon icon; + if( !strBitmapName.isEmpty() ) + { + strBitmapName = QString("%1/Skins/%2.png").arg(QApplication::applicationDirPath()).arg(strBitmapName); + QFileInfo fileInfo(strBitmapName); + if( !fileInfo.exists() ) + { + strBitmapName = QString("%1/Skins/default.png").arg(QApplication::applicationDirPath()); + fileInfo.setFile(strBitmapName); + } + else + mDefaultIcon = false; + + if( fileInfo.exists() ) + icon.addFile(strBitmapName); + } + + if( !icon.isNull() ) + { + mToolButton->setIcon(icon); + } + + mToolButton->setCheckable(true); + mToolButton->setEnabled(false); + this->connect(mToolButton, SIGNAL(clicked(bool)), this, SLOT(clicked(bool))); + + // Only Support appoint Events + //supportsEvent("EventKey"); + registerHandlers(); + return true; +} + +bool ToolPlugin::UnInitialize() +{ + if( mToolButton!=Q_NULLPTR ) + delete mToolButton; + mToolButton = Q_NULLPTR; + + unregisterHandlers(); + return true; +} + +bool ToolPlugin::SetBuddy(x3::IObject* val) +{ + if( m_spBuddy==val ) + return true; + + m_spBuddy = val; + if( !m_spBuddy.valid() ) + { + mToolButton->setEnabled(false); + return false; + } + + mToolButton->setEnabled(true); + + return true; +} + +bool ToolPlugin::readConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ) +{ + if( !((IUIPlugin*)this)->readConfig(node, document, errorMessage) ) + return false; + + return true; +} + +bool ToolPlugin::writeConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ) +{ + if( !((IUIPlugin*)this)->writeConfig(node, document, errorMessage) ) + return false; + + return true; +} + +// IUICommand +QWidget* ToolPlugin::getButtonWidget() +{ + return mToolButton; +} + +QWidget* ToolPlugin::getWndWidget() +{ + return Q_NULLPTR; +} + +// IAnythingEventObserver +bool ToolPlugin::OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam) +{ + if( _stricmp(eventKey.c_str(), "toolActived")==0 ) + { + if( sender==(IUIPlugin*)this ) + return true; + } + return true; +} + +void ToolPlugin::clicked(bool checked) +{ + QMessageBox::information(Q_NULLPTR, "ToolPlugin", checked ? "ToolPlugin clicked" : "ToolPlugin unclicked"); +} diff --git a/plugins/PluginDemo/toolplugin.h b/plugins/PluginDemo/toolplugin.h new file mode 100644 index 0000000..ebd82d7 --- /dev/null +++ b/plugins/PluginDemo/toolplugin.h @@ -0,0 +1,51 @@ +#ifndef TOOLPLUGIN_H +#define TOOLPLUGIN_H +#include +#include + +#include "UIPluginsEvents.h" +#include "UIPlugins.h" +USING_NAMESPACE_CBERSPLUGINS + +const char* const clsidToolPlugin = "clsidToolPlugin"; +class ToolPlugin : public QObject + , public IUIPlugin + , public IUICommand + , public IAnythingEventObserver +{ + Q_OBJECT + X3BEGIN_CLASS_DECLARE(ToolPlugin, clsidToolPlugin) + X3DEFINE_INTERFACE_ENTRY(IUIPlugin) + X3DEFINE_INTERFACE_ENTRY(IUICommand) + X3END_CLASS_DECLARE() + + public: + explicit ToolPlugin(QObject *parent = 0); + ~ToolPlugin(); + +public: + // IUIPlugin + virtual bool Initialize(); + virtual bool UnInitialize(); + virtual bool SetBuddy(x3::IObject* val); + virtual bool readConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ); + virtual bool writeConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ); + + // IUICommand + virtual QWidget* getButtonWidget(); + virtual QWidget* getWndWidget(); + + // IAnythingEventObserver + virtual bool OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam); + +signals: + +public slots: + void clicked(bool checked = false); + +protected: + QToolButton* mToolButton; + bool mDefaultIcon; +}; + +#endif // TOOLPLUGIN_H \ No newline at end of file diff --git a/plugins/PluginDemo/viewplugin.cpp b/plugins/PluginDemo/viewplugin.cpp new file mode 100644 index 0000000..32be2ca --- /dev/null +++ b/plugins/PluginDemo/viewplugin.cpp @@ -0,0 +1,88 @@ +#include "viewplugin.h" +#include +#include +#include +#include + +ViewPlugin::ViewPlugin(QWidget *parent) : QWidget(parent) +{ + Name(QStringLiteral("ViewPlugin")); + Caption(QStringLiteral("View")); + Category(QStringLiteral("Plugins")); + Tooltip(QStringLiteral("ViewPlugin")); + Description(QStringLiteral("ViewPlugin")); + BitmapName(QStringLiteral("ViewPlugin")); + + setWindowTitle(Name()); + +} + +ViewPlugin::~ViewPlugin() +{ + UnInitialize(); +} + +// IUIPlugin +bool ViewPlugin::Initialize() +{ + + // Only Support appoint Events + //supportsEvent("EventKey"); + registerHandlers(); + return true; +} + +bool ViewPlugin::UnInitialize() +{ + + unregisterHandlers(); + hide(); + return true; +} + +bool ViewPlugin::SetBuddy(x3::IObject* val) +{ + if( m_spBuddy==val ) + return true; + + m_spBuddy = val; + if( !m_spBuddy.valid() ) + { + return false; + } + + + return true; +} + +bool ViewPlugin::readConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ) +{ + if( !((IUIPlugin*)this)->readConfig(node, document, errorMessage) ) + return false; + + return true; +} + +bool ViewPlugin::writeConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ) +{ + if( !((IUIPlugin*)this)->writeConfig(node, document, errorMessage) ) + return false; + + return true; +} + +// IUIView +QWidget* ViewPlugin::getViewWidget() +{ + return this; +} + +// IAnythingEventObserver +bool ViewPlugin::OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam) +{ + //if( _stricmp(eventKey.c_str(), "EventKey")==0 ) + //{ + //} + return true; +} + diff --git a/plugins/PluginDemo/viewplugin.h b/plugins/PluginDemo/viewplugin.h new file mode 100644 index 0000000..bd96098 --- /dev/null +++ b/plugins/PluginDemo/viewplugin.h @@ -0,0 +1,45 @@ +#ifndef VIEWPLUGIN_H +#define VIEWPLUGIN_H +#include + +#include "UIPluginsEvents.h" +#include "UIPlugins.h" +USING_NAMESPACE_CBERSPLUGINS + +const char* const clsidViewPlugin = "clsidViewPlugin"; +class ViewPlugin : public QWidget + , public IUIPlugin + , public IUIView + , public IAnythingEventObserver +{ + Q_OBJECT + X3BEGIN_CLASS_DECLARE(ViewPlugin, clsidViewPlugin) + X3DEFINE_INTERFACE_ENTRY(IUIPlugin) + X3DEFINE_INTERFACE_ENTRY(IUIView) + X3END_CLASS_DECLARE() + + public: + explicit ViewPlugin(QWidget *parent = 0); + ~ViewPlugin(); + +public: + // IUIPlugin + virtual bool Initialize(); + virtual bool UnInitialize(); + virtual bool SetBuddy(x3::IObject* val); + virtual bool readConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ); + virtual bool writeConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ); + + // IUIView + virtual QWidget* getViewWidget(); + + // IAnythingEventObserver + virtual bool OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam); + +signals: + +public slots: + +}; + +#endif // VIEWPLUGIN_H \ No newline at end of file diff --git a/plugins/plugins.pro b/plugins/plugins.pro new file mode 100644 index 0000000..45968a5 --- /dev/null +++ b/plugins/plugins.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = PluginDemo \ No newline at end of file diff --git a/x3py/interface/core/iobject.h b/x3py/interface/core/iobject.h new file mode 100644 index 0000000..47ab15e --- /dev/null +++ b/x3py/interface/core/iobject.h @@ -0,0 +1,41 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_IOBJECT_H +#define X3_CORE_IOBJECT_H + +#define BEGIN_NAMESPACE_X3 namespace x3 { +#define END_NAMESPACE_X3 } + +BEGIN_NAMESPACE_X3 + +#ifndef SWIG +inline long _hashkey(const char* str) +{ + unsigned long value = 0; + while (*str) + value = (value<<5) + value + *str++; + return value; +} +#endif + +// IID is unique only in a implement class of a plugin. +#define X3DEFINE_IID(_Interface) \ +public: \ + virtual ~_Interface() {} \ + static const char* getInterfaceName() { return #_Interface; } \ + static long getIID() { static long iid = x3::_hashkey(#_Interface); return iid; } \ + typedef void dummy + +class IObject +{ + X3DEFINE_IID(IObject); +#ifndef SWIG + virtual long retainObject() const = 0; + virtual long releaseObject() const = 0; + virtual bool queryObject(long iid, IObject** p) const = 0; +#endif + virtual const char* getClassID() const = 0; + virtual const char* getClassName() const = 0; +}; + +END_NAMESPACE_X3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/manager/iplugins.h b/x3py/interface/core/manager/iplugins.h new file mode 100644 index 0000000..77b92de --- /dev/null +++ b/x3py/interface/core/manager/iplugins.h @@ -0,0 +1,25 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_IPLUGINS_H +#define X3_CORE_IPLUGINS_H + +#include "x3manager.h" +#include +#include + +BEGIN_NAMESPACE_X3 + +class IPlugins : public IObject +{ + X3DEFINE_IID(IPlugins); + virtual int getPluginCount() const = 0; + virtual void getPluginFiles(std::vector& files) const = 0; + + virtual int getCLSIDCount() const = 0; + virtual const char* getCLSID(int index) = 0; + + virtual int loadExtraPlugins(const char* folder) = 0; + virtual int unloadExtraPlugins() = 0; +}; + +END_NAMESPACE_X3 +#endif diff --git a/x3py/interface/core/manager/iworkpath.h b/x3py/interface/core/manager/iworkpath.h new file mode 100644 index 0000000..e96eaa4 --- /dev/null +++ b/x3py/interface/core/manager/iworkpath.h @@ -0,0 +1,75 @@ +/*! \file iworkpath.h + * \brief Define interface of getting the application's writable path: IAppWorkPath + * \author Zhang Yungui, X3 C++ PluginFramework + * \date 2012.3.4 + */ +#ifndef X3_CORE_IWORKPATH_H +#define X3_CORE_IWORKPATH_H + +#include "x3manager.h" +#include + +BEGIN_NAMESPACE_X3 + +/*! \ingroup _GROUP_APPUI_ + * \interface IAppWorkPath + * \brief interface of getting the application's writable path. + * \see x3::clsidManager, x3::getAppWorkPath() + */ +class IAppWorkPath : public IObject +{ +public: + X3DEFINE_IID(IAppWorkPath); + + //! Get the application's writable absolute path. + /*! The default path is same as getLocalAppDataPath("x3") if setWorkPath() is not called. + \see getLocalAppDataPath, setWorkPath + */ + virtual std::wstring getWorkPath() = 0; + + //! Set the application's writable absolute path. (call before loading plugins) + /*! \see getLocalAppDataPath, getWorkPath + */ + virtual void setWorkPath(const std::wstring& path) = 0; + + //! Returns path as calling SHGetKnownFolderPath(FOLDERID_LocalAppData, ...) + /*! The path form is "X:\Users\auser\AppData\Local\company\" + or the executable file's folder if failed to call SHGetKnownFolderPath(). + \param company append company name to path if not empty. + \return the absolute path. + */ + virtual std::wstring getLocalAppDataPath(const wchar_t* company) = 0; + + //! Returns the language translation path of the current user. + /*! eg: exepath/translations/chs/subfolder (not end with slash char). + \param subfolder sub folder name in the translation path. + \return the language translation path which not end with slash char. + */ + virtual std::wstring getTranslationsPath(const wchar_t* subfolder) = 0; + + virtual std::wstring getConfigPath(const wchar_t* subfolder) = 0; +}; + +//! \copydoc IAppWorkPath::getWorkPath +//! \ingroup _GROUP_APPUI_ +inline std::wstring getAppWorkPath() +{ + return Object(clsidManager)->getWorkPath(); +} + +//! \copydoc IAppWorkPath::getConfigPath +//! \ingroup _GROUP_APPUI_ +inline std::wstring getConfigPath(const wchar_t* subfolder = L"") +{ + return Object(clsidManager)->getConfigPath(subfolder); +} + +//! \copydoc IAppWorkPath::getTranslationsPath +//! \ingroup _GROUP_APPUI_ +inline std::wstring getTranslationsPath(const wchar_t* subfolder) +{ + return Object(clsidManager)->getTranslationsPath(subfolder); +} + +END_NAMESPACE_X3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/manager/x3manager.h b/x3py/interface/core/manager/x3manager.h new file mode 100644 index 0000000..ad6a377 --- /dev/null +++ b/x3py/interface/core/manager/x3manager.h @@ -0,0 +1,12 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_MANAGER_CLSID_H +#define X3_CORE_MANAGER_CLSID_H + +#include + +BEGIN_NAMESPACE_X3 + +const char* const clsidManager = "1137fdae-fd69-4d4c-b3d1-e8f57b55f27e"; + +END_NAMESPACE_X3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/module/classentry.h b/x3py/interface/core/module/classentry.h new file mode 100644 index 0000000..3f7e987 --- /dev/null +++ b/x3py/interface/core/module/classentry.h @@ -0,0 +1,51 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_CLASSENTRY_H +#define X3_CORE_CLASSENTRY_H + +#include "iobject.h" + +BEGIN_NAMESPACE_X3 + +typedef IObject* (*ObjectCreator)(long iid); +typedef bool (*HASIID)(long iid); +enum { MIN_SINGLETON_TYPE = 10 }; + +class ClassEntry +{ +public: + int type; + const char* className; + const char* clsid; + ObjectCreator creator; + HASIID hasiid; + + ClassEntry(int _type, const char* _className, + const char* _clsid, ObjectCreator _creator, HASIID _hasiid) + : type(_type), className(_className), clsid(_clsid) + , creator(_creator), hasiid(_hasiid) + { + } + + ClassEntry() : type(0), className(""), clsid(""), creator(NULL), hasiid(NULL) + { + } + + // see XEND_DEFINE_MODULE, XEND_DEFINE_MODULE_LIB + static const ClassEntry* const classes[]; +}; + +END_NAMESPACE_X3 + +// If don't need plugininc.h or portability/*.h on Windows: +#if !defined(OUTAPI) && defined(_WIN32) +#ifndef _WINDEF_ +#define WIN32_LEAN_AND_MEAN +#include +#endif +#define OUTAPI extern "C" __declspec(dllexport) +#define LOCALAPI +#define x3FreeLibrary(h) FreeLibrary(h) +#define x3LoadLibrary(f) LoadLibraryExA(f, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) +#endif // OUTAPI + +#endif \ No newline at end of file diff --git a/x3py/interface/core/module/classmacro.h b/x3py/interface/core/module/classmacro.h new file mode 100644 index 0000000..e4d76be --- /dev/null +++ b/x3py/interface/core/module/classmacro.h @@ -0,0 +1,49 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_CLASSMACRO_H +#define X3_CORE_CLASSMACRO_H + +// X3BEGIN_CLASS_DECLARE(Cls, clsid) +// X3BEGIN_CLASS_DECLARE0(Cls) +// X3DEFINE_INTERFACE_ENTRY(_Interface) +// X3USE_INTERFACE_ENTRY(_BaseClass) +// X3END_CLASS_DECLARE() + +namespace x3 { +LOCALAPI HMODULE getModuleHandle(); +LOCALAPI HMODULE getManagerModule(); +} + +#define X3BEGIN_CLASS_DECLARE0(Cls) \ +public: \ + static bool _queryObject(const Cls* self, long iid, x3::IObject** p) \ + { + +#define X3BEGIN_CLASS_DECLARE(Cls, clsid) \ +public: \ + static const char* _getClassID() { return clsid; } \ + static const char* _getClassName() { return #Cls; } \ + static bool _queryObject(const Cls* self, long iid, x3::IObject** p) \ + { + +#define X3DEFINE_INTERFACE_ENTRY(_Interface) \ + if (iid == _Interface::getIID()) \ + { \ + if (self) { \ + *p = (x3::IObject*)(_Interface*)(self); \ + (*p)->retainObject(); \ + } \ + return true; \ + } + +#define X3USE_INTERFACE_ENTRY(_BaseClass) \ + if (_BaseClass::_queryObject(self, iid, p)) \ + { \ + return true; \ + } + +#define X3END_CLASS_DECLARE() \ + return false; \ + } \ +protected: // Ensure the following constructor is protected. + +#endif \ No newline at end of file diff --git a/x3py/interface/core/module/moduleitem.h b/x3py/interface/core/module/moduleitem.h new file mode 100644 index 0000000..6b7bcbe --- /dev/null +++ b/x3py/interface/core/module/moduleitem.h @@ -0,0 +1,78 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_MODULEITEM_H +#define X3_CORE_MODULEITEM_H + +namespace x3 { + +class ModuleItem +{ +protected: + ModuleItem() : _index(-1) + { + } + virtual ~ModuleItem() + { + } + + void addModuleItem() + { + _index = InterlockedDecrement(&index()); + if (_index >= 0) + { + items()[_index] = this; // only one thread can do it. + } + } + +public: + static void free() + { + if (items()) + { + for (long i = index(); i < maxCount(); i++) + { + if (i >= 0 && items()[i]) + { + delete items()[i]; + items()[i] = NULL; + } + } + index() = 0; + + delete[] items(); + items() = NULL; + } + } + + static void init(int singletonClassCount) + { + if (!items() && singletonClassCount > 0) + { + maxCount() = (singletonClassCount > maxCount()) + ? singletonClassCount : maxCount(); + index() = maxCount(); + items() = new ModuleItem*[maxCount()]; + } + } + +private: + long _index; // index in the single instance stack. + + static long& maxCount() + { + static long count = 0; + return count; + } + static long& index() + { + static long n = 0; + return n; + } + static ModuleItem**& items() + { + static ModuleItem** p = NULL; + return p; + } +}; + +} // x3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/module/modulemacro.h b/x3py/interface/core/module/modulemacro.h new file mode 100644 index 0000000..c5b7ca9 --- /dev/null +++ b/x3py/interface/core/module/modulemacro.h @@ -0,0 +1,170 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_MODULEMACRO_H +#define X3_CORE_MODULEMACRO_H + +// XBEGIN_DEFINE_MODULE() +// XDEFINE_CLASSMAP_ENTRY(cls) +// XDEFINE_CLASSMAP_ENTRY_Singleton(cls) +// XEND_DEFINE_MODULE() +// XEND_DEFINE_MODULE_DLL() +// XEND_DEFINE_MODULE_MFCEXTDLL() +// XEND_DEFINE_MODULE_MFCDLL() +// XEND_DEFINE_MODULE_LIB(moduleName) +// XDEFINE_EMPTY_MODULE() + +#include "classentry.h" +#include "normalobject.h" +#include "singletonobj.h" + +#define XBEGIN_DEFINE_MODULE() \ + static const x3::ClassEntry s_classes[] = { + +#define XDEFINE_CLASSMAP_ENTRY(cls) \ + x3::ClassEntry(1, "NormalObject<" #cls ">", cls::_getClassID(), \ + (x3::ObjectCreator)(&x3::NormalObject::create), \ + (x3::HASIID)(&x3::NormalObject::hasInterface)), + +#define XDEFINE_CLASSMAP_ENTRY_Singleton(cls) \ + x3::ClassEntry(x3::MIN_SINGLETON_TYPE, \ + "SingletonObject<" #cls ">", cls::_getClassID(), \ + (x3::ObjectCreator)(&x3::SingletonObject::create), \ + (x3::HASIID)(&x3::SingletonObject::hasInterface)), + +#if !defined(_LIB) && !defined(XUSE_LIB_PLUGIN) +#define XEND_DEFINE_MODULE() \ + x3::ClassEntry() \ + }; \ + const x3::ClassEntry* const x3::ClassEntry::classes[] = { \ + s_classes, NULL \ + }; +#else +#define XEND_DEFINE_MODULE() x3::ClassEntry() }; +#endif + +#ifdef _LIB +#define XEND_DEFINE_MODULE_LIB(moduleName) \ + x3::ClassEntry() }; \ + extern const x3::ClassEntry* const classes_##moduleName = s_classes; +#define XEND_DEFINE_MODULE_DLL() +#define XEND_DEFINE_MODULE_MFCEXTDLL() +#define XEND_DEFINE_MODULE_MFCDLL() +#else +#define XEND_DEFINE_MODULE_LIB(moduleName) x3::ClassEntry() }; + +#ifdef _MSC_VER +#pragma warning(disable:4710) // inline function not expanded +#endif + +OUTAPI bool x3InitPlugin(HMODULE hmod, HMODULE); +OUTAPI bool x3FreePlugin(); + +// Call x3DllMain in your DllMain function. +#define x3DllMain(hInstance, dwReason) \ + (dwReason == DLL_PROCESS_ATTACH && ::x3InitPlugin((HMODULE)hInstance, NULL) \ + || dwReason == DLL_PROCESS_DETACH && (::x3FreePlugin() || true)) + +// XEND_DEFINE_MODULE_MFCEXTDLL: for MFC Extension DLL, same as XEND_DEFINE_MODULE_DLL. +// You need to remove your DllMain function or call x3DllMain in your DllMain function. + +#define XEND_DEFINE_MODULE_MFCEXTDLL() \ + XEND_DEFINE_MODULE() \ +static AFX_EXTENSION_MODULE MFCExtDLL = { NULL, NULL }; \ +extern "C" int APIENTRY \ +DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID) \ +{ \ + if (dwReason == DLL_PROCESS_ATTACH) \ + { \ + if (!AfxInitExtensionModule(MFCExtDLL, hInstance)) \ + return 0; \ + new CDynLinkLibrary(MFCExtDLL); \ + return ::x3InitPlugin(MFCExtDLL.hModule, NULL) ? 1 : 0; \ + } \ + else if (dwReason == DLL_PROCESS_DETACH) \ + { \ + ::x3FreePlugin(); \ + AfxTermExtensionModule(MFCExtDLL); \ + } \ + return 1; \ +} + +// XEND_DEFINE_MODULE_MFCDLL: for regular DLL with MFC or MFC application. +// You need to define a instance such as 'CPluginApp theApp;' . +// You may derive a class from CPluginApp instead of CWinApp. + +#define XEND_DEFINE_MODULE_MFCDLL() \ + XEND_DEFINE_MODULE() \ +class CPluginApp : public CWinApp \ +{ \ +public: \ + CPluginApp() \ + { \ + } \ + virtual BOOL InitInstance() \ + { \ + CWinApp::InitInstance(); \ + return ::x3InitPlugin(m_hInstance, NULL); \ + } \ + virtual int ExitInstance() \ + { \ + ::x3FreePlugin(); \ + return CWinApp::ExitInstance(); \ + } \ +}; + +// XEND_DEFINE_MODULE_DLL: for MFC Extension DLL +// You need to remove your DllMain function or call x3DllMain and use XEND_DEFINE_MODULE. + +#if defined(_AFXEXT) && defined(_AFXDLL) && defined(APIENTRY) +#define XEND_DEFINE_MODULE_DLL() \ + XEND_DEFINE_MODULE_MFCEXTDLL() + +// XEND_DEFINE_MODULE_DLL: for regular DLL with MFC or console application with MFC. +// +// If you already have a class derived from CWinApp, then 'theApp' redefinition +// error will occur. You can correct it as the following method: +// 1. call x3InitPlugin and x3FreePlugin in your app class and use XEND_DEFINE_MODULE. +// 2. or use XEND_DEFINE_MODULE_MFCDLL and derive from CPluginApp instead of CWinApp. +// 3. or remove your app class and keep to use XEND_DEFINE_MODULE_DLL. + +#elif defined(_AFXDLL) && defined(__AFXWIN_H__) +#define XEND_DEFINE_MODULE_DLL() \ + XEND_DEFINE_MODULE_MFCDLL() \ + CPluginApp theApp; + +// XEND_DEFINE_MODULE_DLL: for Win32 DLL. +// You need to remove your DllMain function or call x3DllMain and use XEND_DEFINE_MODULE. + +#elif defined(_USRDLL) && defined(APIENTRY) +#ifndef _ATL_DLL +#define XEND_DEFINE_MODULE_DLL() \ + XEND_DEFINE_MODULE() \ +extern "C" BOOL APIENTRY DllMain(HANDLE hmod, DWORD dwReason, LPVOID) \ +{ \ + if (dwReason == DLL_PROCESS_ATTACH) \ + { \ + return ::x3InitPlugin((HMODULE)hmod, NULL); \ + } \ + else if (dwReason == DLL_PROCESS_DETACH) \ + { \ + ::x3FreePlugin(); \ + } \ + return true; \ +} +#else // ATL project +// Please call x3DllMain in your DllMain and use XEND_DEFINE_MODULE instead of XEND_DEFINE_MODULE_DLL. +#define XEND_DEFINE_MODULE_DLL() please_use_XEND_DEFINE_MODULE_and_call_x3DllMain +#endif + +#else +#define XEND_DEFINE_MODULE_DLL() XEND_DEFINE_MODULE() +#endif // XEND_DEFINE_MODULE_DLL + + +#define XDEFINE_EMPTY_MODULE() \ + XBEGIN_DEFINE_MODULE() \ + XEND_DEFINE_MODULE_DLL() \ + OUTAPI bool x3InitializePlugin() { return true; } \ + OUTAPI void x3UninitializePlugin() {} + +#endif // _LIB +#endif \ No newline at end of file diff --git a/x3py/interface/core/module/normalobject.h b/x3py/interface/core/module/normalobject.h new file mode 100644 index 0000000..f06d3d7 --- /dev/null +++ b/x3py/interface/core/module/normalobject.h @@ -0,0 +1,78 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_NORMALOBJECT_H +#define X3_CORE_NORMALOBJECT_H + +#include "iobject.h" + +BEGIN_NAMESPACE_X3 + +template +class NormalObject : public Cls +{ +protected: + NormalObject() : _refcount(1) + { + } + + virtual ~NormalObject() + { + } + +protected: + virtual long retainObject() const + { + return InterlockedIncrement(&_refcount); + } + + virtual long releaseObject() const + { + long ret = InterlockedDecrement(&_refcount); + if (0 == ret) + { + delete this; + } + + return ret; + } + + virtual bool queryObject(long iid, IObject** p) const + { + return Cls::_queryObject(this, iid, p); + } + + virtual const char* getClassID() const + { + return Cls::_getClassID(); + } + + virtual const char* getClassName() const + { + return Cls::_getClassName(); + } + +public: + static IObject* create(long iid) + { + IObject* ret = NULL; + NormalObject* p = new NormalObject(); + + p->queryObject(iid, &ret); + p->releaseObject(); + + return ret; + } + + static bool hasInterface(long iid) + { + return Cls::_queryObject(NULL, iid, NULL); + } + +private: + NormalObject(const NormalObject&); + void operator=(const NormalObject&); + + mutable long _refcount; +}; + +END_NAMESPACE_X3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/module/pluginimpl.h b/x3py/interface/core/module/pluginimpl.h new file mode 100644 index 0000000..d22ee94 --- /dev/null +++ b/x3py/interface/core/module/pluginimpl.h @@ -0,0 +1,206 @@ +#if !defined(X3_CORE_PLUGINIMPL_H) && !defined(_LIB) +#define X3_CORE_PLUGINIMPL_H + +#include "classentry.h" +#include "moduleitem.h" +#ifdef X3_CORE_PORTABILITY_H +#include "../portability/portimpl.h" +#endif +#ifdef X3_LOG_DEBUGR_H_ +#include +#endif + +BEGIN_NAMESPACE_X3 + +static HMODULE s_hmod = NULL; +static HMODULE s_manager = NULL; +static bool s_loadmgr = false; +static long s_refcount = 0; + +OUTAPI bool x3InitializePlugin(); +OUTAPI void x3UninitializePlugin(); + +LOCALAPI HMODULE getModuleHandle() +{ + return s_hmod; +} + +LOCALAPI HMODULE getManagerModule() +{ + return s_manager; +} + +static int getClassCount(int minType = 0) +{ + int count = 0; + + for (const ClassEntry* const* arr = ClassEntry::classes; *arr; arr++) + { + for (const ClassEntry* cls = *arr; cls->creator; cls++) + { + if (cls->type >= minType) + count++; + } + } + + return count; +} + +static const char** getClassIDs(const char** clsids, int count) +{ + const ClassEntry* const* arr = ClassEntry::classes; + int i = 0; + + for (; *arr && i < count; arr++) + { + for (const ClassEntry* cls = *arr; cls->creator; cls++, i++) + { + clsids[i] = cls->clsid; + } + } + clsids[i] = NULL; + + return clsids; +} + +static bool getDefaultClassID(long iid, const char*& clsid) +{ + for (const ClassEntry* const* arr = ClassEntry::classes; *arr; arr++) + { + for (const ClassEntry* cls = *arr; cls->creator; cls++) + { + if (cls->hasiid(iid)) + { + clsid = cls->clsid; + return true; + } + } + } + + return false; +} + +OUTAPI bool x3InternalCreate(const char* clsid, long iid, IObject** p) +{ + *p = NULL; + + if (0 == *clsid) + { + getDefaultClassID(iid, clsid); + } + for (const ClassEntry* const* arr = ClassEntry::classes; *arr; arr++) + { + for (const ClassEntry* cls = *arr; cls->creator; cls++) + { + if (strcmp(cls->clsid, clsid) == 0) + { + *p = cls->creator(iid); + return *p != NULL; + } + } + } + + return false; +} + +OUTAPI bool x3FreePlugin() +{ + if (--s_refcount != 0) + return false; + + bool needFree = true; + + if (s_manager && s_manager != s_hmod) + { + typedef bool (*CF)(const char*, long, IObject**); + typedef bool (*UF)(CF); + UF uf = (UF)GetProcAddress(s_manager, "x3UnregisterPlugin"); + needFree = !uf || uf(x3InternalCreate); + } + if (needFree) + { + x3UninitializePlugin(); + } + + if (s_loadmgr) + { + x3FreeLibrary(s_manager); + s_loadmgr = false; + } + + ModuleItem::free(); + + return true; +} + +#ifndef X3_CLASS_MAXCOUNT +#define X3_CLASS_MAXCOUNT 64 +#endif +#ifndef X3MANAGER_PLNAME +#define X3MANAGER_PLNAME "x3manager.pln" +#endif + +OUTAPI bool x3InitPlugin(HMODULE hmod, HMODULE hmanager) +{ + if (++s_refcount != 1) + return true; + + int singletonClassCount = getClassCount(MIN_SINGLETON_TYPE); + ModuleItem::init(singletonClassCount); + + // Call all interfaces' getIID() to set static const value. + const char* tmpclsid; + getDefaultClassID(IObject::getIID(), tmpclsid); + + s_hmod = hmod; + + if (!s_manager) + { + hmanager = hmanager ? hmanager : GetModuleHandleA(X3MANAGER_PLNAME); + if (!hmanager) + { + hmanager = x3LoadLibrary(X3MANAGER_PLNAME); + s_loadmgr = true; + } + s_manager = hmanager; + } + + bool needInit = true; + + if (s_manager && s_manager != s_hmod) + { + typedef bool (*CF)(const char*, long, IObject**); + typedef bool (*RF)(CF, HMODULE, const char**); + RF freg = (RF)GetProcAddress(s_manager, "x3RegisterPlugin"); + + const char* clsids[X3_CLASS_MAXCOUNT + 1] = { NULL }; + needInit = !freg || freg(x3InternalCreate, s_hmod, + getClassIDs(clsids, X3_CLASS_MAXCOUNT)); + } + + return !needInit || x3InitializePlugin(); +} + +#ifndef CREATEOBJECTIMPL +#define CREATEOBJECTIMPL +LOCALAPI bool createObject(const char* clsid, long iid, IObject** p) +{ + if (!x3InternalCreate(clsid, iid, p) && s_manager) + { + typedef bool (*F)(const char*, long, IObject**); + F f = (F)GetProcAddress(s_manager, "x3CreateObject"); + return f && f(clsid, iid, p); + } + return *p != NULL; +} +#endif + +#ifndef X3_EXCLUDE_CREATEOBJECT +OUTAPI bool x3CreateObject(const char* clsid, long iid, IObject** p) +{ + return x3InternalCreate(clsid, iid, p); +} +#endif + +END_NAMESPACE_X3 +#endif diff --git a/x3py/interface/core/module/plugininc.h b/x3py/interface/core/module/plugininc.h new file mode 100644 index 0000000..ae67a12 --- /dev/null +++ b/x3py/interface/core/module/plugininc.h @@ -0,0 +1,10 @@ +#ifndef X3_CORE_PLUGIN_INC_H +#define X3_CORE_PLUGIN_INC_H + +#include +#include + +//#include +//#include + +#endif \ No newline at end of file diff --git a/x3py/interface/core/module/singletonobj.h b/x3py/interface/core/module/singletonobj.h new file mode 100644 index 0000000..399e96f --- /dev/null +++ b/x3py/interface/core/module/singletonobj.h @@ -0,0 +1,114 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_SINGLETONOBJECT_H +#define X3_CORE_SINGLETONOBJECT_H + +#include "moduleitem.h" +#include "iobject.h" + +#if !defined(_MSC_VER) || _MSC_VER >= 1700 +#include +#endif + +BEGIN_NAMESPACE_X3 + +template +class SingletonObject + : public Cls + , public ModuleItem +{ +protected: + SingletonObject() : _refcount(1) + { + } + + virtual ~SingletonObject() + { + if (Instance() == this) + { + Instance() = NULL; + } + } + +protected: + virtual long retainObject() const + { + return InterlockedIncrement(&_refcount); + } + + virtual long releaseObject() const + { + return InterlockedDecrement(&_refcount); + } + + virtual bool queryObject(long iid, IObject** p) const + { + return Cls::_queryObject(this, iid, p); + } + + virtual const char* getClassID() const + { + return Cls::_getClassID(); + } + + virtual const char* getClassName() const + { + return Cls::_getClassName(); + } + +public: + static IObject* create(long iid) + { + if (!Instance()) + { +#if !defined(_MSC_VER) || _MSC_VER >= 1700 + static std::mutex s_mutex; + std::lock_guard lock(s_mutex); + if (!Instance()) + { + SingletonObject* p = new SingletonObject(); + Instance() = p; + p->addModuleItem(); + } +#else + static long s_count = 0; + SingletonObject* p = new SingletonObject(); + + if (1 == InterlockedIncrement(&s_count)) + { + Instance() = p; + p->addModuleItem(); + } + else + { + delete p; // created by another thread + } + InterlockedDecrement(&s_count); +#endif + } + + IObject* ret = NULL; + Instance()->queryObject(iid, &ret); + + return ret; + } + + static bool hasInterface(long iid) + { + return Cls::_queryObject(NULL, iid, NULL); + } + +private: + SingletonObject(const SingletonObject&); + void operator=(const SingletonObject&); + + mutable long _refcount; + + static SingletonObject*& Instance() + { + static SingletonObject* obj = NULL; + return obj; + } +}; + +END_NAMESPACE_X3 +#endif diff --git a/x3py/interface/core/nonplugin/scanplugins.h b/x3py/interface/core/nonplugin/scanplugins.h new file mode 100644 index 0000000..07e41ef --- /dev/null +++ b/x3py/interface/core/nonplugin/scanplugins.h @@ -0,0 +1,85 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_NONPLUGIN_SCANPLUGINS_H +#define X3_NONPLUGIN_SCANPLUGINS_H + +#include +#include + +#if defined(X3_CORE_PORTABILITY_H) && !defined(X3_EXCLUDE_CREATEOBJECT) +#include +#endif + +#ifndef PLUGINS_MAXCOUNT +#define PLUGINS_MAXCOUNT 1000 +#endif + +namespace x3 { + +static HMODULE s_modules[PLUGINS_MAXCOUNT] = { NULL }; +static int s_nmods = 0; + +static bool loadfilter(const char* filename, const char* ext) +{ + if (_stricmp(ext, ".pln") == 0 + && GetModuleHandleA(PathFindFileNameA(filename)) == NULL) + { + s_modules[s_nmods] = x3LoadLibrary(filename); + if (s_modules[s_nmods]) + s_nmods++; + } + return s_nmods < PLUGINS_MAXCOUNT; +} + +int loadScanPlugins(const char* folder = "plugins") +{ + char path[MAX_PATH]; + + GetModuleFileNameA(NULL, path, MAX_PATH); + PathRemoveFileSpecA(path); + PathAppendA(path, folder); + + // Load x3manager before others, so others can find it in x3InitPlugin(). + if (!GetModuleHandleA("x3manager.pln")) + { + PathAppendA(path, "x3manager.pln"); + loadfilter(path, ".pln"); + PathRemoveFileSpecA(path); + } + + typedef int (*LOADF)(const char*); + LOADF fload = (LOADF)GetProcAddress(GetModuleHandleA("x3manager.pln"), "x3LoadPlugins"); + int extcount = fload ? fload(folder) : 0; + + if (!fload) // load plugins regardless the x3manager plugin. + x3::scanfiles(loadfilter, path, true); + + return s_nmods + extcount; +} + +void unloadScanPlugins() +{ + typedef int (*UF)(); + UF uf = (UF)GetProcAddress(GetModuleHandleA("x3manager.pln"), "x3UnloadPlugins"); + if (uf) uf(); + + while (s_nmods > 0) + { + x3FreeLibrary(s_modules[--s_nmods]); + } +} + +#if !defined(X3_EXCLUDE_CREATEOBJECT) && !defined(CREATEOBJECTIMPL) +#define CREATEOBJECTIMPL + +class IObject; +LOCALAPI bool createObject(const char* clsid, long iid, IObject** p) +{ + typedef bool (*F)(const char*, long, IObject**); + F f = (F)GetProcAddress(s_modules[0], "x3CreateObject"); + return f && f(clsid, iid, p); +} +HMODULE getManagerModule() { return s_modules[0]; } +#endif // CREATEOBJECTIMPL + +} // x3 +#endif diff --git a/x3py/interface/core/nonplugin/swigext.h b/x3py/interface/core/nonplugin/swigext.h new file mode 100644 index 0000000..f27d1c9 --- /dev/null +++ b/x3py/interface/core/nonplugin/swigext.h @@ -0,0 +1,35 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_NONPLUGIN_SWIG_EXT_H +#define X3_NONPLUGIN_SWIG_EXT_H + +#if defined(SWIGPYTHON) || defined(SWIGCSHARP) || \ + defined(USE_PYTHON) || defined(USE_CSHARP) + #define SELF_PRE "_" +#else + #define SELF_PRE "" +#endif + +#if defined(_WIN32) && (defined(SWIGPYTHON) || defined(USE_PYTHON)) + #define SELF_EXT ".pyd" +#elif !defined(SWIGINLINE) // not in swig wrapper file. + #define SELF_EXT ".pln" +#elif defined(_WIN32) + #define SELF_EXT ".dll" +#else + #define SELF_EXT ".so" +#endif + +// the internal plugin (*.pln) 's relative folder base on the current module. +// +#ifndef PLUGIN_PATH +#ifdef SWIGPYTHON // in python wrapper file. +#define CURMOD_IN_CWDSUBDIR // see x3LoadLibrary() in uniximpl.h +#define PLUGIN_PATH "../../plugins/" // python module has a package +#elif defined(SWIGINLINE) // in swig wrapper file. +#define PLUGIN_PATH "../plugins/" +#else +#define PLUGIN_PATH "" +#endif +#endif // PLUGIN_PATH + +#endif diff --git a/x3py/interface/core/nonplugin/useplugin.h b/x3py/interface/core/nonplugin/useplugin.h new file mode 100644 index 0000000..3b16ab5 --- /dev/null +++ b/x3py/interface/core/nonplugin/useplugin.h @@ -0,0 +1,51 @@ +// x3py framework: https://github.com/rhcad/x3py +#if !defined(X3_NONPLUGIN_USE_PLUGIN_H) && !defined(X3_NONPLUGIN_USE_PLUGINS_H) +#define X3_NONPLUGIN_USE_PLUGIN_H + +#include +#include "swigext.h" + +// PLUGIN_PATH: the internal plugin (*.pln) 's relative folder. +// PLUGIN_NAME: the internal plugin name, no extension and path. +// SELF_MODULE_NAME: file name of the caller module which will load the internal plugin. +// SELF_MODULE: defined when the caller name hasn't PLUGIN_NAME. + +#ifdef PLUGIN_NAME + +#ifndef SELF_MODULE_NAME +#ifndef SELF_MODULE +#define SELF_MODULE_NAME SELF_PRE PLUGIN_NAME SELF_EXT +#else +#define SELF_MODULE_NAME SELF_PRE SELF_MODULE SELF_EXT +#endif +#endif // SELF_MODULE_NAME + +#if defined(X3_CORE_PORTABILITY_H) && !defined(X3_EXCLUDE_CREATEOBJECT) +#include "../portability/portimpl.h" +#endif + +namespace x3 { + +static LoadModuleHelper loader(PLUGIN_PATH PLUGIN_NAME ".pln", + GetModuleHandleA(SELF_MODULE_NAME)); + +#if !defined(X3_EXCLUDE_CREATEOBJECT) && !defined(CREATEOBJECTIMPL) +#define CREATEOBJECTIMPL + +HMODULE getManagerModule() +{ + return loader.getModule(); +} + +class IObject; +bool createObject(const char* clsid, long iid, IObject** p) +{ + typedef bool (*F)(const char*, long, IObject**); + F f = (F)loader.getFunc("x3CreateObject"); + return f && f(clsid, iid, p); +} +#endif // CREATEOBJECTIMPL + +} // x3 +#endif // PLUGIN_NAME +#endif diff --git a/x3py/interface/core/nonplugin/useplugins.h b/x3py/interface/core/nonplugin/useplugins.h new file mode 100644 index 0000000..3531fcd --- /dev/null +++ b/x3py/interface/core/nonplugin/useplugins.h @@ -0,0 +1,94 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_NONPLUGIN_USE_PLUGINS_H +#define X3_NONPLUGIN_USE_PLUGINS_H + +#include +#include "swigext.h" + +// PLUGIN_PATH: the internal plugin (*.pln) 's relative folder. +// SELF_MODULE_NAME: file name of the caller module which will load the internal plugins. +// SELF_MODULE: used to make SELF_MODULE_NAME. + +#ifndef SELF_MODULE_NAME +#ifndef SELF_MODULE +#define SELF_MODULE_NAME NULL // application file name +#else +#define SELF_MODULE_NAME SELF_PRE SELF_MODULE SELF_EXT +#endif +#endif // SELF_MODULE_NAME + +#if defined(X3_CORE_PORTABILITY_H) && !defined(X3_EXCLUDE_CREATEOBJECT) +#include "../portability/portimpl.h" +#endif + +namespace x3 { + +static LoadModuleHelper* s_plugins[20] = { NULL }; +static int s_nplugin = 0; + +#if !defined(X3_EXCLUDE_CREATEOBJECT) && !defined(CREATEOBJECTIMPL) +#define CREATEOBJECTIMPL + +HMODULE getManagerModule() +{ + return s_plugins[0] ? s_plugins[0]->getModule() : NULL; +} + +class IObject; +bool createObject(const char* clsid, long iid, IObject** p) +{ + typedef bool (*F)(const char*, long, IObject**); + F f = !s_plugins[0] ? NULL : (F)s_plugins[0]->getFunc("x3CreateObject"); + return f && f(clsid, iid, p); +} +#endif // CREATEOBJECTIMPL + +int loadPlugins(const char* const* plugins, const char* folder = PLUGIN_PATH) +{ + HMODULE basemod = GetModuleHandleA(SELF_MODULE_NAME); + + for (int i = 0; s_nplugin < 20 - 1 && plugins[i]; ++i) + { + LoadModuleHelper* p = new LoadModuleHelper(); + if (p->load(plugins[i], basemod, folder)) + { + s_plugins[s_nplugin++] = p; + } + else + { + delete p; + } + } + + return s_nplugin; +} + +void unloadPlugins() +{ + for (int i = s_nplugin - 1; i >= 0; i--) + { + delete s_plugins[i]; + s_plugins[i] = NULL; + } + s_nplugin = 0; +} + +/** \code + * const char* plugins[] = { "x3manager.pln", "myplugin.pln", NULL }; + * x3::AutoLoadPlugins autoload(plugins, "plugins"); + * \endcode + */ +struct AutoLoadPlugins +{ + AutoLoadPlugins(const char* const* plugins, const char* folder = PLUGIN_PATH) + { + loadPlugins(plugins, folder); + } + ~AutoLoadPlugins() + { + unloadPlugins(); + } +}; + +} // x3 +#endif diff --git a/x3py/interface/core/objptr.h b/x3py/interface/core/objptr.h new file mode 100644 index 0000000..f751afc --- /dev/null +++ b/x3py/interface/core/objptr.h @@ -0,0 +1,166 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_OBJPTR_H +#define X3_CORE_OBJPTR_H + +#include "iobject.h" + +BEGIN_NAMESPACE_X3 + +#ifndef SWIG +LOCALAPI bool createObject(const char* clsid, long iid, IObject** p); +struct NullPointerError {}; +#ifndef X3THROW_NULLPOINTERERROR +#define X3THROW_NULLPOINTERERROR(name) throw x3::NullPointerError() +#endif +#endif // SWIG + +template class Object +{ +public: + // if clsid is "" then the actual class id will be used just in the current plugin. + Object(const char* clsid) : _p((I*)0) + { + createObject(clsid, I::getIID(), address()); + } + + Object(const IObject* src) : _p((I*)0) + { + operator=(src); + } + +#if !defined(_MSC_VER) || _MSC_VER > 1200 + Object(const Object& src) : _p((I*)0) + { + operator=(src.p()); + } +#endif // not vc6 + + bool valid() const + { + return !!_p; + } + + I* p() const + { + return _p; + } + + I* operator->() const + { + if (!_p) { + X3THROW_NULLPOINTERERROR(I::getInterfaceName()); + } + return _p; + } + +#ifndef SWIG // SWIG always call operator->() so must create when constructing. + Object() : _p((I*)0) + { + } + + template + Object(const Object& src) : _p((I*)0) + { + operator=(src.p()); + } + + ~Object() + { + release(); + } + + void release() + { + if (_p) { + _p->releaseObject(); + _p = (I*)0; + } + } + + Object& create(const char* clsid = "") + { + createObject(clsid, I::getIID(), address()); + return *this; + } + +#if !defined(_MSC_VER) || _MSC_VER > 1200 + Object& operator=(const Object& src) + { + if (src) + src.p()->retainObject(); + if (_p) + _p->releaseObject(); + _p = src.p(); + + return *this; + } +#endif // not vc6 + + template + Object& operator=(const Object& src) + { + if (I::getIID() == I2::getIID() + || I::getIID() == IObject::getIID()) + { + if (src) + src.p()->retainObject(); + if (_p) + _p->releaseObject(); + _p = src.p(); + + return *this; + } + + return operator=(src.p()); + } + + Object& operator=(const IObject* src) + { + if (_p != src) { + release(); + if (I::getIID() == IObject::getIID() && src) { + src->retainObject(); + _p = static_cast(const_cast(src)); + } + else if (src) { + src->queryObject(I::getIID(), address()); + } + } + return *this; + } + + operator bool() const + { + return !!_p; + } + + bool operator!() const + { + return !_p; + } + + bool operator==(const Object& src) const + { + return _p == src._p; + } + + bool operator!=(const Object& src) const + { + return _p != src._p; + } + + IObject** address() + { + release(); + return reinterpret_cast(&_p); + } +#endif // SWIG + +private: + I* _p; +}; + +typedef Object AnyObject; + +END_NAMESPACE_X3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/observer/eventobserver.h b/x3py/interface/core/observer/eventobserver.h new file mode 100644 index 0000000..f4a34af --- /dev/null +++ b/x3py/interface/core/observer/eventobserver.h @@ -0,0 +1,54 @@ +// x3py framework: https://github.com/rhcad/x3py +// Need to include in module.cpp +// +#ifndef X3_CORE_EVENTOBSERVER_H +#define X3_CORE_EVENTOBSERVER_H + +#include + +namespace x3 { + +bool registerObserver(const char* type, PROC handler); +bool registerObserver(const char* type, ObserverObject* obj, ON_EVENT handler); +void unregisterObserver(ObserverObject* obj); +int fireEvent(const char* type, PROC dispatcher, void* data, bool obj); + +} // x3 + + +#ifndef JOIN +# define JOIN(a,b) JOIN1(a,b) +# define JOIN1(a,b) a##b +#endif + +// Declare a event type. +// Return: return type of the handler function, such as void or bool. +// Params: param types of the handler function. eg: (void), (int&), (int, char c). +// Namespace: extra string of event type. +#define X3DEFINE_EVENT(TypeName, Return, Params, Namespace) \ + struct TypeName { \ + static const char* getType() { return #TypeName "." Namespace; } \ + typedef Return (*Handler)Params; \ + } + +// Declare a event type for classes derived from ObserverObject. +#define X3DEFINE_OBJEVENT(TypeName, Return, Params, Namespace) \ + struct TypeName { \ + static const char* getType() { return #TypeName "." Namespace; } \ + typedef Return (x3::ObserverObject::*Handler)Params; \ + } + +// Register a handler function in x3InitializePlugin(). +// handler: local function or static member function. +#define X3_REGISTER_OBSERVER(TypeName, handler) \ + x3::registerObserver(TypeName::getType(), \ + (PROC)static_cast(handler)) + +// Register a member function and object in the constructor function. +// handler: member function of a class derived from x3::ObserverObject. +// Note: must callHandler x3::unregisterObserver(this) in the destructor function. +#define X3_REGISTER_OBSERVER_OBJECT(TypeName, handler) \ + x3::registerObserver(TypeName::getType(), this, \ + (x3::ON_EVENT)static_cast(handler)) + +#endif \ No newline at end of file diff --git a/x3py/interface/core/observer/fireevent.h b/x3py/interface/core/observer/fireevent.h new file mode 100644 index 0000000..7a1f001 --- /dev/null +++ b/x3py/interface/core/observer/fireevent.h @@ -0,0 +1,161 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_FIRE_EVENT_H +#define X3_CORE_FIRE_EVENT_H + +#include + +#define X3DEFINE_EVENT_0(TypeName, Namespace) \ + X3DEFINE_EVENT(TypeName, void, (), Namespace); \ + typedef x3::FireEvent0 Fire ## TypeName + +#define X3DEFINE_EVENT_0Break(TypeName, Namespace) \ + X3DEFINE_EVENT(TypeName, bool, (), Namespace); \ + typedef x3::FireEvent0 Fire ## TypeName + +#define X3DEFINE_EVENT_1(TypeName, ParamT, Namespace) \ + X3DEFINE_EVENT(TypeName, void, (ParamT), Namespace); \ + typedef x3::FireEvent1 Fire ## TypeName + +#define X3DEFINE_EVENT_1Break(TypeName, ParamT, Namespace) \ + X3DEFINE_EVENT(TypeName, bool, (ParamT), Namespace); \ + typedef x3::FireEvent1 Fire ## TypeName + +#define X3DEFINE_EVENT_2(TypeName, Param1, Param2, Namespace) \ + X3DEFINE_EVENT(TypeName, void, (Param1, Param2), Namespace); \ + typedef x3::FireEvent2 Fire ## TypeName + +#define X3DEFINE_EVENT_2Break(TypeName, Param1, Param2, Namespace) \ + X3DEFINE_EVENT(TypeName, bool, (Param1, Param2), Namespace); \ + typedef x3::FireEvent2 Fire ## TypeName + +// ---------------------------------------- + +namespace x3 { + +template class FireEventBase +{ +public: + int nhandled; + + bool handled() const { return nhandled > 0; } + +protected: + FireEventBase() : nhandled(0) {} + + typedef bool (*EventDispatcher)(PROC handler, void* data); + + template + void _fireEvent(Dispatcher dispatcher) { + nhandled = fireEvent(EventType::getType(), + (PROC)static_cast(dispatcher), this, false); + } +}; + +// -------------- FireEvent0 -------------- + +struct FireEvent0NotBreak { + template + static bool call(Handler handler) { handler(); return true; } +}; + +struct FireEvent0Break { + template + static bool call(Handler handler) { return !!handler(); } +}; + +template +class FireEvent0 : public FireEventBase +{ +public: + typedef FireEventBase Base; + typedef FireEvent0 This; + FireEvent0() {} + This& fireEvent() { Base::_fireEvent(dispatcher); return *this; } + +private: + static bool dispatcher(PROC handler, void*) { + return Break::call((typename EventType::Handler)handler); + } +}; + +// -------------- FireEvent1 -------------- + +struct FireEvent1NotBreak { + template + static bool call(Handler handler, ParamT* param) { + handler(*param); return true; + } +}; + +struct FireEvent1Break { + template + static bool call(Handler handler, ParamT* param) { + return !!handler(*param); + } +}; + +template +class FireEvent1 : public FireEventBase +{ +public: + typedef FireEventBase Base; + typedef FireEvent1 This; + ParamT param; + + FireEvent1(ParamT p) : param(p) {} + This& fireEvent() { Base::_fireEvent(dispatcher); return *this; } + +private: + FireEvent1(const This&); + This& operator=(const This&); + FireEvent1(); + + static bool dispatcher(PROC handler, void* data) { + return Break::call((typename EventType::Handler)handler, &((This*)data)->param); + } +}; + +// -------------- FireEvent2 -------------- + +struct FireEvent2NotBreak { + template + static bool call(Handler handler, Param1* param1, Param2* param2) { + handler(*param1, *param2); return true; + } +}; + +struct FireEvent2Break { + template + static bool call(Handler handler, Param1* param1, Param2* param2) { + return !!handler(*param1, *param2); + } +}; + +template +class FireEvent2 : public FireEventBase +{ +public: + typedef FireEventBase Base; + typedef FireEvent2 This; + Param1 param1; + Param2 param2; + + FireEvent2(Param1 p1, Param2 p2) : param1(p1), param2(p2) {} + This& fireEvent() { Base::_fireEvent(dispatcher); return *this; } + +private: + FireEvent2(const This&); + This& operator=(const This&); + FireEvent2(); + + static bool dispatcher(PROC handler, void* data) { + This* p = (This*)data; + return Break::call((typename EventType::Handler)handler, &p->param1, &p->param2); + } +}; + +} // x3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/observer/fireeventex.h b/x3py/interface/core/observer/fireeventex.h new file mode 100644 index 0000000..eb362aa --- /dev/null +++ b/x3py/interface/core/observer/fireeventex.h @@ -0,0 +1,165 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_FIRE_EVENTEX_H +#define X3_CORE_FIRE_EVENTEX_H + +#include + +#define X3DEFINE_EVENT_3(TypeName, Param1, Param2, Param3, Namespace) \ + X3DEFINE_EVENT(TypeName, void, (Param1, Param2, Param3), Namespace); \ + typedef x3::FireEvent3 Fire ## TypeName + +#define X3DEFINE_EVENT_3Break(TypeName, Param1, Param2, Param3, Namespace) \ + X3DEFINE_EVENT(TypeName, bool, (Param1, Param2, Param3), Namespace); \ + typedef x3::FireEvent3 Fire ## TypeName + +#define X3DEFINE_EVENT_4(TypeName, Param1, Param2, Param3, Param4, Namespace) \ + X3DEFINE_EVENT(TypeName, void, (Param1, Param2, Param3, Param4), Namespace); \ + typedef x3::FireEvent4 Fire ## TypeName + +#define X3DEFINE_EVENT_4Break(TypeName, Param1, Param2, Param3, Param4, Namespace) \ + X3DEFINE_EVENT(TypeName, bool, (Param1, Param2, Param3, Param4), Namespace); \ + typedef x3::FireEvent4 Fire ## TypeName + +#define X3DEFINE_EVENT_5(TypeName, Param1, Param2, Param3, Param4, Param5, Namespace) \ + X3DEFINE_EVENT(TypeName, void, (Param1, Param2, Param3, Param4, Param5), Namespace); \ + typedef x3::FireEvent5 Fire ## TypeName + +#define X3DEFINE_EVENT_5Break(TypeName, Param1, Param2, Param3, Param4, Param5, Namespace) \ + X3DEFINE_EVENT(TypeName, bool, (Param1, Param2, Param3, Param4, Param5), Namespace); \ + typedef x3::FireEvent5 Fire ## TypeName + +// ---------------------------------------- + +namespace x3 { + +// -------------- FireEvent3 -------------- + +struct FireEvent3NotBreak { + template + static bool call(Handler handler, Param1* param1, Param2* param2, Param3* param3) { + handler(*param1, *param2, *param3); return true; + } +}; + +struct FireEvent3Break { + template + static bool call(Handler handler, Param1* param1, Param2* param2, Param3* param3) { + return !!handler(*param1, *param2, *param3); + } +}; + +template +class FireEvent3 : public FireEventBase +{ +public: + typedef FireEventBase Base; + typedef FireEvent3 This; + Param1 param1; + Param2 param2; + Param3 param3; + + FireEvent3(Param1 p1, Param2 p2, Param3 p3) : param1(p1), param2(p2), param3(p3) {} + This& fireEvent() { Base::_fireEvent(dispatcher); return *this; } + +private: + FireEvent3(const This&); + This& operator=(const This&); + FireEvent3(); + + static bool dispatcher(PROC handler, void* data) { + This* p = (This*)data; + return Break::call((typename EventType::Handler)handler, &p->param1, &p->param2, &p->param3); + } +}; + +// -------------- FireEvent4 -------------- + +struct FireEvent4NotBreak { + template + static bool call(Handler handler, Param1* param1, Param2* param2, Param3* param3, Param4* param4) { + handler(*param1, *param2, *param3, *param4); return true; + } +}; + +struct FireEvent4Break { + template + static bool call(Handler handler, Param1* param1, Param2* param2, Param3* param3, Param4* param4) { + return !!handler(*param1, *param2, *param3, *param4); + } +}; + +template +class FireEvent4 : public FireEventBase +{ +public: + typedef FireEventBase Base; + typedef FireEvent4 This; + Param1 param1; + Param2 param2; + Param3 param3; + Param4 param4; + + FireEvent4(Param1 p1, Param2 p2, Param3 p3, Param4 p4) : param1(p1), param2(p2), param3(p3), param4(p4) {} + This& fireEvent() { Base::_fireEvent(dispatcher); return *this; } + +private: + FireEvent4(const This&); + This& operator=(const This&); + FireEvent4(); + + static bool dispatcher(PROC handler, void* data) { + This* p = (This*)data; + return Break::call((typename EventType::Handler)handler, &p->param1, &p->param2, &p->param3, &p->param4); + } +}; + +// -------------- FireEvent5 -------------- + +struct FireEvent5NotBreak { + template + static bool call(Handler handler, Param1* param1, Param2* param2, Param3* param3, Param4* param4, Param5* param5) { + handler(*param1, *param2, *param3, *param4, *param5); return true; + } +}; + +struct FireEvent5Break { + template + static bool call(Handler handler, Param1* param1, Param2* param2, Param3* param3, Param4* param4, Param5* param5) { + return !!handler(*param1, *param2, *param3, *param4, *param5); + } +}; + +template +class FireEvent5 : public FireEventBase +{ +public: + typedef FireEventBase Base; + typedef FireEvent5 This; + Param1 param1; + Param2 param2; + Param3 param3; + Param4 param4; + Param5 param5; + + FireEvent5(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) : param1(p1), param2(p2), param3(p3), param4(p4), param5(p5) {} + This& fireEvent() { Base::_fireEvent(dispatcher); return *this; } + +private: + FireEvent5(const This&); + This& operator=(const This&); + FireEvent5(); + + static bool dispatcher(PROC handler, void* data) { + This* p = (This*)data; + return Break::call((typename EventType::Handler)handler, &p->param1, &p->param2, &p->param3, &p->param4, &p->param5); + } +}; + +} // x3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/observer/fireobjevent.h b/x3py/interface/core/observer/fireobjevent.h new file mode 100644 index 0000000..1eefa04 --- /dev/null +++ b/x3py/interface/core/observer/fireobjevent.h @@ -0,0 +1,237 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_FIRE_OBJECT_EVENT_H +#define X3_CORE_FIRE_OBJECT_EVENT_H + +#include + +#define X3DEFINE_OBJEVENT_0(TypeName, Namespace) \ + X3DEFINE_OBJEVENT(TypeName, void, (), Namespace); \ + typedef x3::FireObjectEvent0 Fire ## TypeName + +#define X3DEFINE_OBJEVENT_0Break(TypeName, Namespace) \ + X3DEFINE_OBJEVENT(TypeName, bool, (), Namespace); \ + typedef x3::FireObjectEvent0 Fire ## TypeName + +#define X3DEFINE_OBJEVENT_1(TypeName, ParamT, Namespace) \ + X3DEFINE_OBJEVENT(TypeName, void, (ParamT), Namespace); \ + typedef x3::FireObjectEvent1 Fire ## TypeName + +#define X3DEFINE_OBJEVENT_1Break(TypeName, ParamT, Namespace) \ + X3DEFINE_OBJEVENT(TypeName, bool, (ParamT), Namespace); \ + typedef x3::FireObjectEvent1 Fire ## TypeName + +#define X3DEFINE_OBJEVENT_2(TypeName, Param1, Param2, Namespace) \ + X3DEFINE_OBJEVENT(TypeName, void, (Param1, Param2), Namespace); \ + typedef x3::FireObjectEvent2 Fire ## TypeName + +#define X3DEFINE_OBJEVENT_2Break(TypeName, Param1, Param2, Namespace) \ + X3DEFINE_OBJEVENT(TypeName, bool, (Param1, Param2), Namespace); \ + typedef x3::FireObjectEvent2 Fire ## TypeName + +#define X3DEFINE_OBJEVENT_3(TypeName, Param1, Param2, Param3, Namespace) \ + X3DEFINE_OBJEVENT(TypeName, void, (Param1, Param2, Param3), Namespace); \ + typedef x3::FireObjectEvent3 Fire ## TypeName + +#define X3DEFINE_OBJEVENT_3Break(TypeName, Param1, Param2, Param3, Namespace) \ + X3DEFINE_OBJEVENT(TypeName, bool, (Param1, Param2, Param3), Namespace); \ + typedef x3::FireObjectEvent3 Fire ## TypeName +// ---------------------------------------- + +namespace x3 { + +template class FireObjEventBase +{ +public: + int nhandled; + + bool handled() const { return nhandled > 0; } + +protected: + FireObjEventBase() : nhandled(0) {} + + typedef bool (*EventDispatcher)(ObserverObject*, ON_EVENT, void* data); + + template + void _fireEvent(Dispatcher dispatcher) { + nhandled = fireEvent(EventType::getType(), + (PROC)static_cast(dispatcher), this, true); + } + + template + static void cast(Handler& result, ON_EVENT handler) { + union Funcs { + ON_EVENT pfn; + Handler handler; + }; + Funcs f; + f.pfn = handler; + result = f.handler; + } +}; + +// -------------- FireObjectEvent0 -------------- + +struct FireObjectEvent0NotBreak { + template + static bool call(ObserverObject* obj, Handler handler) { + (obj->*handler)(); return true; + } +}; + +struct FireObjectEvent0Break { + template + static bool call(ObserverObject* obj, Handler handler) { + return !!(obj->*handler)(); + } +}; + +template +class FireObjectEvent0 : public FireObjEventBase +{ +public: + typedef FireObjEventBase Base; + typedef FireObjectEvent0 This; + FireObjectEvent0() {} + This& fireEvent() { Base::_fireEvent(dispatcher); return *this; } + +private: + static bool dispatcher(ObserverObject* obj, ON_EVENT hd, void*) { + typename EventType::Handler handler; + Base::cast(handler, hd); + return Break::call(obj, handler); + } +}; + +// -------------- FireObjectEvent1 -------------- + +struct FireObjectEvent1NotBreak { + template + static bool call(ObserverObject* obj, Handler hd, ParamT* param) { + (obj->*hd)(*param); return true; + } +}; + +struct FireObjectEvent1Break { + template + static bool call(ObserverObject* obj, Handler hd, ParamT* param) { + return !!(obj->*hd)(*param); + } +}; + +template +class FireObjectEvent1 : public FireObjEventBase +{ +public: + typedef FireObjEventBase Base; + typedef FireObjectEvent1 This; + ParamT param; + + FireObjectEvent1(ParamT p) : param(p) {} + This& fireEvent() { Base::_fireEvent(dispatcher); return *this; } + +private: + FireObjectEvent1(const This&); + This& operator=(const This&); + FireObjectEvent1(); + + static bool dispatcher(ObserverObject* obj, ON_EVENT hd, void* data) { + typename EventType::Handler handler; + Base::cast(handler, hd); + return Break::call(obj, handler, &((This*)data)->param); + } +}; + +// -------------- FireObjectEvent2 -------------- + +struct FireObjectEvent2NotBreak { + template + static bool call(ObserverObject* obj, Handler hd, Param1* p1, Param2* p2) { + (obj->*hd)(*p1, *p2); return true; + } +}; + +struct FireObjectEvent2Break { + template + static bool call(ObserverObject* obj, Handler hd, Param1* p1, Param2* p2) { + return !!(obj->*hd)(*p1, *p2); + } +}; + +template +class FireObjectEvent2 : public FireObjEventBase +{ +public: + typedef FireObjEventBase Base; + typedef FireObjectEvent2 This; + Param1 param1; + Param2 param2; + + FireObjectEvent2(Param1 p1, Param2 p2) : param1(p1), param2(p2) {} + This& fireEvent() { Base::_fireEvent(dispatcher); return *this; } + +private: + FireObjectEvent2(const This&); + This& operator=(const This&); + FireObjectEvent2(); + + static bool dispatcher(ObserverObject* obj, ON_EVENT hd, void* data) + { + This* p = (This*)data; + typename EventType::Handler handler; + + Base::cast(handler, hd); + return Break::call(obj, handler, &p->param1, &p->param2); + } +}; + +// -------------- FireObjectEvent3 -------------- + +struct FireObjectEvent3NotBreak { + template + static bool call(ObserverObject* obj, Handler hd, Param1* p1, Param2* p2,Param3* p3) { + (obj->*hd)(*p1, *p2, *p3); return true; + } +}; + +struct FireObjectEvent3Break { + template + static bool call(ObserverObject* obj, Handler hd, Param1* p1, Param2* p2,Param3* p3) { + return !!(obj->*hd)(*p1, *p2,*p3); + } +}; + +template +class FireObjectEvent3 : public FireObjEventBase +{ +public: + typedef FireObjEventBase Base; + typedef FireObjectEvent3 This; + Param1 param1; + Param2 param2; + Param3 param3; + + FireObjectEvent3(Param1 p1, Param2 p2,Param3 p3) : param1(p1), param2(p2),param3(p3) {} + This& fireEvent() { Base::_fireEvent(dispatcher); return *this; } + +private: + FireObjectEvent3(const This&); + This& operator=(const This&); + FireObjectEvent3(); + + static bool dispatcher(ObserverObject* obj, ON_EVENT hd, void* data) + { + This* p = (This*)data; + typename EventType::Handler handler; + + Base::cast(handler, hd); + return Break::call(obj, handler, &p->param1, &p->param2,&p->param3); + } +}; +} // x3 +#endif diff --git a/x3py/interface/core/observer/fireobjeventex.h b/x3py/interface/core/observer/fireobjeventex.h new file mode 100644 index 0000000..daefcd8 --- /dev/null +++ b/x3py/interface/core/observer/fireobjeventex.h @@ -0,0 +1,123 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_FIRE_OBJECT_EVENTEX_H +#define X3_CORE_FIRE_OBJECT_EVENTEX_H + +#include + +#define X3DEFINE_OBJEVENT_4(TypeName, Param1, Param2, Param3, Param4, Namespace) \ + X3DEFINE_OBJEVENT(TypeName, void, (Param1, Param2, Param3, Param4), Namespace); \ + typedef x3::FireObjectEvent4 Fire ## TypeName + +#define X3DEFINE_OBJEVENT_4Break(TypeName, Param1, Param2, Param3, Param4, Namespace) \ + X3DEFINE_OBJEVENT(TypeName, bool, (Param1, Param2, Param3, Param4), Namespace); \ + typedef x3::FireObjectEvent4 Fire ## TypeName + +#define X3DEFINE_OBJEVENT_5(TypeName, Param1, Param2, Param3, Param4, Param5, Namespace) \ + X3DEFINE_OBJEVENT(TypeName, void, (Param1, Param2, Param3, Param4, Param5), Namespace); \ + typedef x3::FireObjectEvent5 Fire ## TypeName + +#define X3DEFINE_OBJEVENT_5Break(TypeName, Param1, Param2, Param3, Param4, Param5, Namespace) \ + X3DEFINE_OBJEVENT(TypeName, bool, (Param1, Param2, Param3, Param4, Param5), Namespace); \ + typedef x3::FireObjectEvent5 Fire ## TypeName + +// ---------------------------------------- + +namespace x3 { + +// -------------- FireObjectEvent4 -------------- + +struct FireObjectEvent4NotBreak { + template + static bool call(ObserverObject* obj, Handler hd, Param1* p1, Param2* p2, Param3* p3, Param4* p4) { + (obj->*hd)(*p1, *p2, *p3, *p4); return true; + } +}; + +struct FireObjectEvent4Break { + template + static bool call(ObserverObject* obj, Handler hd, Param1* p1, Param2* p2, Param3* p3, Param4* p4) { + return !!(obj->*hd)(*p1, *p2, *p3, *p4); + } +}; + +template +class FireObjectEvent4 : public FireObjEventBase +{ +public: + typedef FireObjEventBase Base; + typedef FireObjectEvent4 This; + Param1 param1; + Param2 param2; + Param3 param3; + Param4 param4; + + FireObjectEvent4(Param1 p1, Param2 p2, Param3 p3, Param4 p4) : param1(p1), param2(p2), param3(p3), param4(p4) {} + This& fireEvent() { Base::_fireEvent(dispatcher); return *this; } + +private: + FireObjectEvent4(const This&); + This& operator=(const This&); + FireObjectEvent4(); + + static bool dispatcher(ObserverObject* obj, ON_EVENT hd, void* data) + { + This* p = (This*)data; + typename EventType::Handler handler; + + Base::cast(handler, hd); + return Break::call(obj, handler, &p->param1, &p->param2, &p->param3, &p->param4); + } +}; + +// -------------- FireObjectEvent5 -------------- + +struct FireObjectEvent5NotBreak { + template + static bool call(ObserverObject* obj, Handler hd, Param1* p1, Param2* p2, Param3* p3, Param4* p4, Param5* p5) { + (obj->*hd)(*p1, *p2, *p3, *p4, *p5); return true; + } +}; + +struct FireObjectEvent5Break { + template + static bool call(ObserverObject* obj, Handler hd, Param1* p1, Param2* p2, Param3* p3, Param4* p4, Param5* p5) { + return !!(obj->*hd)(*p1, *p2, *p3, *p4, *p5); + } +}; + +template +class FireObjectEvent5 : public FireObjEventBase +{ +public: + typedef FireObjEventBase Base; + typedef FireObjectEvent5 This; + Param1 param1; + Param2 param2; + Param3 param3; + Param4 param4; + Param5 param5; + + FireObjectEvent5(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) : param1(p1), param2(p2), param3(p3), param4(p4), param5(p5) {} + This& fireEvent() { Base::_fireEvent(dispatcher); return *this; } + +private: + FireObjectEvent5(const This&); + This& operator=(const This&); + FireObjectEvent5(); + + static bool dispatcher(ObserverObject* obj, ON_EVENT hd, void* data) + { + This* p = (This*)data; + typename EventType::Handler handler; + + Base::cast(handler, hd); + return Break::call(obj, handler, &p->param1, &p->param2, &p->param3, &p->param4, &p->param5); + } +}; + +} // x3 +#endif diff --git a/x3py/interface/core/observer/observerimpl.h b/x3py/interface/core/observer/observerimpl.h new file mode 100644 index 0000000..02d489d --- /dev/null +++ b/x3py/interface/core/observer/observerimpl.h @@ -0,0 +1,44 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_OBSERVERIMPL_H +#define X3_CORE_OBSERVERIMPL_H + +#include + +#ifndef X3_CORE_PLUGINIMPL_H +#define x3InternalCreate createObject +#endif + +namespace x3 { + +bool registerObserver(const char* type, PROC handler) +{ + typedef bool (*CF)(const char*, long, IObject**); + typedef bool (*F)(const char*, PROC, CF); + F f = (F)GetProcAddress(getManagerModule(), "x3RegisterObserver"); + return f && f(type, handler, x3InternalCreate); +} + +bool registerObserver(const char* type, x3::ObserverObject* obj, x3::ON_EVENT handler) +{ + typedef bool (*CF)(const char*, long, IObject**); + typedef bool (*F)(const char*, x3::ObserverObject*, x3::ON_EVENT, CF); + F f = (F)GetProcAddress(getManagerModule(), "x3RegisterObserverObject"); + return f && f(type, obj, handler, x3InternalCreate); +} + +void unregisterObserver(x3::ObserverObject* obj) +{ + typedef void (*F)(x3::ObserverObject*); + F f = (F)GetProcAddress(getManagerModule(), "x3UnregisterObserverObject"); + if (f) f(obj); +} + +int fireEvent(const char* type, PROC dispatcher, void* data, bool obj) +{ + typedef int (*F)(const char*, PROC, void*); + F f = (F)GetProcAddress(getManagerModule(), obj ? "x3FireObjectEvent" : "x3FireEvent"); + return f ? f(type, dispatcher, data) : 0; +} + +} // x3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/observer/observerobject.h b/x3py/interface/core/observer/observerobject.h new file mode 100644 index 0000000..75a1894 --- /dev/null +++ b/x3py/interface/core/observer/observerobject.h @@ -0,0 +1,16 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_OBSERVEROBJECT_H +#define X3_CORE_OBSERVEROBJECT_H + +namespace x3 { + +class ObserverObject +{ +public: + virtual ~ObserverObject() {} +}; + +typedef void (ObserverObject::*ON_EVENT)(); + +} // x3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/portability/func_s.h b/x3py/interface/core/portability/func_s.h new file mode 100644 index 0000000..39d0b8a --- /dev/null +++ b/x3py/interface/core/portability/func_s.h @@ -0,0 +1,176 @@ +//! \file func_s.h +//! \brief Realize functions compatible with VC++ 6.0 and below + +#ifndef FUNCTIONS_COMPATIBLE_VC60_H +#define FUNCTIONS_COMPATIBLE_VC60_H + +#if !defined(_MSC_VER) || _MSC_VER < 1400 // not VC8 + +#ifdef __GNUC__ +#include +#include +#endif + +#if defined(_STDIO_DEFINED) // stdio.h + +inline int sprintf_s(char *buffer, size_t, const char *format, ...) +{ + va_list arglist; + va_start(arglist, format); + return vsprintf(buffer, format, arglist); +} + +inline int swprintf_s(wchar_t *buffer, size_t size, const wchar_t *format, ...) +{ + va_list arglist; + va_start(arglist, format); +#if !defined(_WIN32) + return vswprintf(buffer, size, format, arglist); +#else + size; return vswprintf(buffer, format, arglist); +#endif +} + +inline int vsprintf_s(char *buffer, size_t, const char *format, va_list arglist) + { return vsprintf(buffer, format, arglist); } + +inline int vswprintf_s(wchar_t *buffer, size_t size, const wchar_t *format, va_list arglist) +#if !defined(_WIN32) + { return vswprintf(buffer, size, format, arglist); } +#else + { size; return vswprintf(buffer, format, arglist); } +#endif + +#endif // _INC_STDIO + +inline int strcpy_s(char *str, size_t size, const char *src) + { return strncpy(str, src, size) ? 0 : -1; } +inline int wcscpy_s(wchar_t *str, size_t size, const wchar_t *src) + { return wcsncpy(str, src, size) ? 0 : -1; } + +inline int strncpy_s(char *str, size_t size, const char *src, size_t len) + { return strncpy(str, src, size < len ? size : len) ? 0 : -1; } +inline int wcsncpy_s(wchar_t *str, size_t size, const wchar_t *src, size_t len) + { return wcsncpy(str, src, size < len ? size : len) ? 0 : -1; } + +inline int strcat_s(char *str, size_t, const char *src) + { return strcat(str, src) ? 0 : -1; } +inline int wcscat_s(wchar_t *str, size_t, const wchar_t *src) + { return wcscat(str, src) ? 0 : -1; } + +inline wchar_t * _wcslwr_s(wchar_t *str) + { for (wchar_t* p = str; *p; p++) towlower(*p); return str; } +inline wchar_t * _wcsupr_s(wchar_t *str) + { for (wchar_t* p = str; *p; p++) towupper(*p); return str; } + +#if defined(_WIN32) + +inline int _ltoa_s(long value, char *str, size_t, int radix) + { _ltoa(value, str, radix); return errno; } +inline int _ltow_s(long value, wchar_t *str, size_t, int radix) + { _ltow(value, str, radix); return errno; } +inline int _itoa_s(int value, char *str, size_t, int radix) + { _itoa(value, str, radix); return errno; } +inline int _itow_s(int value, wchar_t *str, size_t, int radix) + { _itow(value, str, radix); return errno; } +inline int _ultow_s(unsigned long value, wchar_t *str, size_t, int radix) + { _ultow(value, str, radix); return errno; } + +#elif defined(_STDIO_DEFINED) + +inline int _ltoa_s(long value, char *str, size_t size, int radix) + { sprintf_s(str, size, 16 == radix ? "%lx" : "%ld", value); return 0; } +inline int _ltow_s(long value, wchar_t *str, size_t size, int radix) + { swprintf_s(str, size, 16 == radix ? L"%lx" : L"%ld", value); return 0; } +inline int _itoa_s(int value, char *str, size_t size, int radix) + { return _ltoa_s(value, str, size, radix); } +inline int _itow_s(int value, wchar_t *str, size_t size, int radix) + { return _ltow_s(value, str, size, radix); } +inline int _ultow_s(unsigned long value, wchar_t *str, size_t size, int radix) + { swprintf_s(str, size, 16 == radix ? L"%ulx" : L"%uld", value); return 0; } + +#endif + +#if (defined(_INC_STDLIB) || defined(_STDLIB_H_)) && defined(_WIN32) + +inline int _splitpath_s( + const char * path, char * drive, size_t, + char * dir, size_t, + char * fname, size_t, + char * ext, size_t) +{ + _splitpath(path, drive, dir, fname, ext); + return errno; +} + +inline int _wsplitpath_s( + const wchar_t * path, wchar_t * drive, size_t, + wchar_t * dir, size_t, + wchar_t * fname, size_t, + wchar_t * ext, size_t) +{ + _wsplitpath(path, drive, dir, fname, ext); + return errno; +} + +inline int _makepath_s(char *path, size_t, + const char *drive, const char *dir, const char *fname, const char *ext) +{ + _makepath(path, drive, dir, fname, ext); + return errno; +} + +inline int _wmakepath_s(wchar_t *path, size_t, + const wchar_t *drive, const wchar_t *dir, const wchar_t *fname, const wchar_t *ext) +{ + _wmakepath(path, drive, dir, fname, ext); + return errno; +} + +#endif // _INC_STDLIB + +#ifdef _INC_TIME // time.h +inline void localtime_s(struct tm *tmOut, const time_t *timer) +{ + struct tm * p = localtime(timer); + if (tmOut != NULL && p != NULL) + *tmOut = *p; +} +#endif // _INC_TIME + +#define _sopen_s(fileHandler, filename, oflag, pmode, rw) \ + (*fileHandler = _open(filename, oflag, pmode), errno) + +#ifdef UNICODE +#define _stprintf_s swprintf_s +#define _vstprintf_s vswprintf_s +#define _tcscpy_s wcscpy_s +#define _tcsncpy_s wcsncpy_s +#define _tcscat_s wcscat_s +#define _tsplitpath_s _wsplitpath_s +#define _tmakepath_s _wmakepath_s +#define _ltot_s _ltow_s +#define _itot_s _itow_s +#else +#define _stprintf_s sprintf_s +#define _vstprintf_s vsprintf_s +#define _tcscpy_s strcpy_s +#define _tcsncpy_s strncpy_s +#define _tcscat_s strcat_s +#define _tsplitpath_s _splitpath_s +#define _tmakepath_s _makepath_s +#define _ltot_s _ltoa_s +#define _itot_s _itoa_s +#endif // UNICODE + +#endif // _MSC_VER + +#ifndef GET_WHEEL_DELTA_WPARAM +#define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam)) +#endif + +#ifndef _countof +#define _countof(array) (sizeof(array)/sizeof(array[0])) +#endif + +#endif // FUNCTIONS_COMPATIBLE_VC60_H diff --git a/x3py/interface/core/portability/pathstr.h b/x3py/interface/core/portability/pathstr.h new file mode 100644 index 0000000..f793102 --- /dev/null +++ b/x3py/interface/core/portability/pathstr.h @@ -0,0 +1,126 @@ +/*! \file pathstr.h + * \brief Included by portimpl.h to implement path functions. + * \author Zhang Yungui, X3 C++ PluginFramework + * \date 2011.5.23 + */ +#ifndef X3_PORTABILITY_PATHSTR_IMPL_H +#define X3_PORTABILITY_PATHSTR_IMPL_H + +static inline bool IsPathSlash(char c) +{ + return '\\' == c || '/' == c; +} + +char* PathFindFileNameA(const char* path) +{ + const char* p1 = path ? strrchr(path, '\\') : NULL; + const char* p2 = path ? strrchr(path, '/') : NULL; + + p1 = !p1 || (p2 && p2 > p1) ? p2 : p1; + + return const_cast(p1 ? p1 + 1 : path); +} + +char* PathFindExtensionA(const char* path) +{ + char* p = PathFindFileNameA(path); + char* ext = p ? strrchr(p, '.') : p; + return ext ? ext : p; +} + +bool PathIsRelativeA(const char* path) +{ + return path && strrchr(path, ':') == NULL && path[0] != '\\' && path[0] != '/'; +} + +void PathStripPathA(char* path) +{ + PathRemoveBackslashA(path); + char* filename = PathFindFileNameA(path); + + if (filename && filename > path) + { + while (*filename) + { + *path++ = *filename++; + } + *path = *filename; + } +} + +void PathRemoveFileSpecA(char* path) +{ + PathRemoveBackslashA(path); + char* filename = PathFindFileNameA(path); + + if (filename && filename > path) + { + *(filename - 1) = 0; + } +} + +void PathRemoveExtensionA(char* path) +{ + char* dot = path ? strrchr(path, '.') : NULL; + + if (dot) + { + *dot = 0; + } +} + +void PathRemoveBackslashA(char* path) +{ + size_t len = path ? strlen(path) : 0; + + if (len > 0 && IsPathSlash(path[len - 1])) + { + path[len - 1] = 0; + } +} + +void PathAppendA(char* path, const char* more) +{ + ASSERT(path && more); + + if (path[0] && '.' == more[0] && '.' == more[1]) + { + PathRemoveFileSpecA(path); + PathAppendA(path, more[2] ? more + 3 : more + 2); + return; + } + + size_t len = strlen(path); + + if (len > 0 && !IsPathSlash(path[len - 1]) && *more) + { + strcat(path, "/"); + } + strcat(path, IsPathSlash(*more) ? more + 1 : more); +} + +char* PathAddBackslashA(char* path) +{ + size_t len = path ? strlen(path) : 0; + + if (len > 0 && !IsPathSlash(path[len - 1])) + { + strcat(path, "/"); + } + + return path; +} + +void PathRenameExtensionA(char* path, const char* more) +{ + ASSERT(path && more); + char* dot = strrchr(path, '.'); + + if (!dot) + { + dot = path + strlen(path); + } + strcpy(dot, more); +} + +#endif \ No newline at end of file diff --git a/x3py/interface/core/portability/portimpl.h b/x3py/interface/core/portability/portimpl.h new file mode 100644 index 0000000..db7f5bb --- /dev/null +++ b/x3py/interface/core/portability/portimpl.h @@ -0,0 +1,24 @@ +// Implement portability functions. +// This file has included by XModuleImpl.h and XComCreator.h + +#ifndef X3_PORTABILITY_IMPL_H +#define X3_PORTABILITY_IMPL_H + +#include "x3port.h" + +#ifndef ASSERT +#define ASSERT(expr) +#define VERIFY(expr) expr +#endif + +#ifndef _INC_SHLWAPI +#include "pathstr.h" +#endif + +#ifdef _WIN32 +#include "winimpl.h" +#else +#include "uniximpl.h" +#endif + +#endif \ No newline at end of file diff --git a/x3py/interface/core/portability/uniximpl.h b/x3py/interface/core/portability/uniximpl.h new file mode 100644 index 0000000..cc1f3a6 --- /dev/null +++ b/x3py/interface/core/portability/uniximpl.h @@ -0,0 +1,209 @@ +// Included by portimpl.h to implement functions on Linux. +// __linux__ or __APPLE__ is defined. + +#ifndef X3LINUX_PORTABILITY_IMPL_H +#define X3LINUX_PORTABILITY_IMPL_H + +#include "x3unix.h" +#include +#include +#include // getcwd + +static HMODULE _hmod = NULL; +static HMODULE _manager = NULL; +static char _filename[MAX_PATH] = ""; + +OUTAPI bool _ondlopen(HMODULE hmod, const char* filename, HMODULE hmanager) +{ + _hmod = hmod; + _manager = hmanager; + strncpy(_filename, filename, MAX_PATH); + + typedef bool (*F)(HMODULE, HMODULE); + F f = (F)GetProcAddress(hmod, "x3InitPlugin"); + + return !f || f(hmod, _manager); +} + +OUTAPI bool _getdlname(char* filename, int size) +{ + return !!strncpy(filename, _filename, size); +} + +static inline void seterr(const char* err) +{ + if (err) {} +} + +bool x3FreeLibrary(HMODULE hmod) +{ + typedef void (*F)(); + F f = (F)GetProcAddress(hmod, "x3FreePlugin"); + if (f) f(); + + int ret = hmod ? dlclose(hmod) : 0; + seterr(dlerror()); + return 0 == ret; +} + +HMODULE x3LoadLibrary(const char* filename) +{ + char fullpath[MAX_PATH]; + HMODULE hmod = NULL; + + if (!filename) { + return NULL; + } + if (PathIsRelativeA(filename)) + { + if (!hmod && _filename[0]) // base on the current module + { + strcpy(fullpath, _filename); + PathRemoveFileSpecA(fullpath); + PathAppendA(fullpath, filename); + hmod = dlopen(fullpath, RTLD_LAZY); + } + if (!hmod) // base on the current process + { + GetModuleFileNameA(NULL, fullpath, MAX_PATH); + if (fullpath[0]) { + PathRemoveFileSpecA(fullpath); + PathAppendA(fullpath, filename); + hmod = dlopen(fullpath, RTLD_LAZY); + } + } + if (!hmod) // base on the current direction + { + getcwd(fullpath, MAX_PATH); +#ifdef CURMOD_IN_CWDSUBDIR + if (_strnicmp(filename, "../", 3) == 0) filename += 3; +#endif + PathAppendA(fullpath, filename); + hmod = dlopen(fullpath, RTLD_LAZY); + } + if (hmod) { + filename = fullpath; + } + } + if (!hmod) + { + hmod = dlopen(filename, RTLD_LAZY); + seterr(dlerror()); + } + + if (hmod) + { + if (0 == strcmp("x3manager.pln", PathFindFileNameA(filename))) + { + _manager = hmod; + } + + typedef bool (*F)(HMODULE, const char*, HMODULE); + F f = (F)GetProcAddress(hmod, "_ondlopen"); + if (f && !f(hmod, filename, _manager)) + { + x3FreeLibrary(hmod); + hmod = NULL; + } + } + + return hmod; +} + +void* GetProcAddress(HMODULE hmod, const char* name) +{ + void* sym = NULL; + + if (hmod) + { + sym = dlsym(hmod, name); + seterr(dlerror()); + } + + return sym; +} + +HMODULE GetModuleHandleA(const char* filename) +{ + if (!filename) + { + return NULL; + } + if (PathIsRelativeA(filename) + && 0 == strcmp(PathFindFileNameA(filename), PathFindFileNameA(_filename))) + { + return _hmod; + } + + typedef HMODULE (*F)(const char*); + F f = (F)GetProcAddress(_manager, "unixFindModule"); + + return f ? f(filename) : NULL; +} + +void GetModuleFileNameA(HMODULE hmod, char* filename, int size) +{ + *filename = 0; + + if (!hmod) + { + size_t bytes = readlink("/proc/self/exe", filename, size); + if (bytes > 0) + filename[bytes < size - 1 ? bytes : size - 1] = '\0'; + } + else + { + typedef bool (*F)(char*, int); + F f = (F)GetProcAddress(hmod, "_getdlname"); + if (f) f(filename, size); + } +} + +DWORD GetLastError() +{ + return 0; +} + +int WideCharToMultiByte(int /*codepage*/, DWORD /*flags*/, + const wchar_t* wstr, int wchars, + char* astr, int achars, + const char*, void*) +{ + return (int)(astr ? wcstombs(astr, wstr, achars) : (wchars * sizeof(char))); +} + +int MultiByteToWideChar(int /*codepage*/, DWORD /*flags*/, + const char* astr, int achars, + wchar_t* wstr, int wchars) +{ + return wstr ? (int)mbstowcs(wstr, astr, wchars) : achars; +} + +int _stricmp(const char* s1, const char* s2) +{ + return strncasecmp(s1, s2, strlen(s1)); +} + +int _strnicmp(const char* s1, const char* s2, int count) +{ + return strncasecmp(s1, s2, count); +} + +long InterlockedIncrement(long* p) +{ + return ++(*p); +} + +long InterlockedDecrement(long* p) +{ + return --(*p); +} + +long InterlockedExchange(long* p, long v) +{ + long old = *p; + *p = v; + return old; +} + +#endif diff --git a/x3py/interface/core/portability/winimpl.h b/x3py/interface/core/portability/winimpl.h new file mode 100644 index 0000000..1a5fff9 --- /dev/null +++ b/x3py/interface/core/portability/winimpl.h @@ -0,0 +1,37 @@ +// Included by portimpl.h to implement functions on Windows. + +#ifndef X3WIN_PORTABILITY_IMPL_H +#define X3WIN_PORTABILITY_IMPL_H + +#include "x3win.h" + +bool x3FreeLibrary(HMODULE hdll) +{ +#ifdef __GNUC__ + typedef void (*F)(); + F f = (F)GetProcAddress(hdll, "x3FreePlugin"); + if (f) f(); +#endif + return !!FreeLibrary(hdll); +} + +HMODULE x3LoadLibrary(const char* filename) +{ + HMODULE hdll = LoadLibraryExA(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + + if( GetProcAddress(hdll, "DllMain")==nullptr ) + { + typedef bool (*F)(HMODULE, HMODULE); + F f = (F)GetProcAddress(hdll, "x3InitPlugin"); + + if (f && !f(hdll, NULL)) + { + x3FreeLibrary(hdll); + hdll = NULL; + } + } + + return hdll; +} + +#endif diff --git a/x3py/interface/core/portability/x3port.h b/x3py/interface/core/portability/x3port.h new file mode 100644 index 0000000..8c89041 --- /dev/null +++ b/x3py/interface/core/portability/x3port.h @@ -0,0 +1,34 @@ +#ifndef X3_CORE_PORTABILITY_H +#define X3_CORE_PORTABILITY_H + +#if defined(_WIN64) && !defined(_WIN32) +#define _WIN32 +#endif + +#ifdef _WIN32 +#include "x3win.h" +#else +#include "x3unix.h" +#endif + +#if !defined(_MSC_VER) || _MSC_VER < 1400 +#include "func_s.h" +#endif + +HMODULE x3LoadLibrary(const char* filename); +bool x3FreeLibrary(HMODULE hdll); + +#ifndef _INC_SHLWAPI +char* PathFindFileNameA(const char* path); +char* PathFindExtensionA(const char* path); +bool PathIsRelativeA(const char* path); +void PathStripPathA(char* path); +void PathRemoveFileSpecA(char* path); +void PathRemoveExtensionA(char* path); +void PathRemoveBackslashA(char* path); +void PathAppendA(char* path, const char* more); +char* PathAddBackslashA(char* path); +void PathRenameExtensionA(char* path, const char* more); +#endif + +#endif \ No newline at end of file diff --git a/x3py/interface/core/portability/x3unix.h b/x3py/interface/core/portability/x3unix.h new file mode 100644 index 0000000..10186a3 --- /dev/null +++ b/x3py/interface/core/portability/x3unix.h @@ -0,0 +1,52 @@ +// Included by X3Portability.h to declare functions on linux or macosx. + +#ifndef X3UNIX_PORTABILITY_H +#define X3UNIX_PORTABILITY_H + +#include +#include +#include + +#define OUTAPI extern "C" __attribute__((visibility("default"))) +#if defined(__APPLE__) +#define LOCALAPI +#else +#define LOCALAPI __attribute__((visibility("hidden"))) +#endif + +#ifndef MAX_PATH +#define MAX_PATH 512 +#endif + +typedef void* HMODULE; +typedef void* HANDLE; +typedef void* HWND; +typedef void* PROC; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef uint32_t DWORD; +typedef unsigned long ULONG; + +long InterlockedIncrement(long* p); +long InterlockedDecrement(long* p); +long InterlockedExchange(long* p, long v); + +bool x3FreeLibrary(HMODULE hdll); +HMODULE x3LoadLibrary(const char* filename); +HMODULE GetModuleHandleA(const char* filename); +PROC GetProcAddress(HMODULE hdll, const char* name); +void GetModuleFileNameA(HMODULE hdll, char* filename, int size); +DWORD GetLastError(); + +int WideCharToMultiByte(int codepage, DWORD flags, + const wchar_t* wstr, int wchars, + char* astr, int achars, + const char* defaultChar, void*); +int MultiByteToWideChar(int codepage, DWORD flags, + const char* astr, int achars, + wchar_t* wstr, int wchars); + +int _stricmp(const char* s1, const char* s2); +int _strnicmp(const char* s1, const char* s2, int count); + +#endif diff --git a/x3py/interface/core/portability/x3win.h b/x3py/interface/core/portability/x3win.h new file mode 100644 index 0000000..fae8613 --- /dev/null +++ b/x3py/interface/core/portability/x3win.h @@ -0,0 +1,50 @@ +// Included by X3Portability.h to declare functions on Windows. + +#ifndef X3WIN_PORTABILITY_H +#define X3WIN_PORTABILITY_H + +#if !defined(_MSC_VER) || _MSC_VER > 1200 // not VC6 + +#ifndef WINVER +#define WINVER 0x0501 // WinXP or later. +#endif + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT WINVER +#endif +#ifndef _WIN32_WINDOWS +#define _WIN32_WINDOWS WINVER +#endif +#ifndef _WIN32_IE +#define _WIN32_IE 0x0600 // IE6 or later. +#endif + +#endif // _MSC_VER + +#ifdef _AFXDLL +#define VC_EXTRALEAN +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS +#define _AFX_ALL_WARNINGS +#include // MFC core and standard components +#include // MFC extensions +#ifndef _AFX_NO_OLE_SUPPORT +#include // MFC Automation classes +#endif +#else +#define _WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#include // Windows master include file +#endif // _AFXDLL + +#ifdef _MSC_VER +#include // Windows light-weight utility APIs +#pragma comment(lib, "shlwapi.lib") +#endif + +#ifdef __GNUC__ +#define OUTAPI extern "C" __attribute__((dllexport)) +#else +#define OUTAPI extern "C" __declspec(dllexport) +#endif +#define LOCALAPI + +#endif \ No newline at end of file diff --git a/x3py/interface/core/utilfunc/convstr.h b/x3py/interface/core/utilfunc/convstr.h new file mode 100644 index 0000000..44fc922 --- /dev/null +++ b/x3py/interface/core/utilfunc/convstr.h @@ -0,0 +1,132 @@ +// x3c - C++ PluginFramework +//! \file convstr.h +//! \brief Define functions to convert between UNICODE string and ANSI string. + +#ifndef UTILFUNC_CONVSTR_H_ +#define UTILFUNC_CONVSTR_H_ + +#include +#include + +#ifndef CP_UTF8 +#define CP_UTF8 65001 +#endif + +namespace x3 { + +//! Convert from UNICODE string to ANSI string, x3::w2a. +/*! + \ingroup _GROUP_UTILFUNC + \param s The source UNICODE string to be converted. + \param codepage Code page of the target ANSI string. For example CP_UTF8 is UTF-8 code. + \return The target ANSI string. +*/ +inline std::string w2a(const wchar_t* s, int codepage = 0) +{ + std::string str; + int wlen = (NULL == s) ? 0 : (int)wcslen(s); + + if (wlen > 0) + { + int len = WideCharToMultiByte(codepage, 0, s, wlen, NULL, 0, NULL, NULL); + str.resize(len); + WideCharToMultiByte(codepage, 0, s, wlen, + const_cast(str.data()), len, NULL, NULL); + } + + return str; +} + +//! Convert from UNICODE string to ANSI string, x3::w2a. +/*! + \ingroup _GROUP_UTILFUNC + \param s The source UNICODE string to be converted. + \param codepage Code page of the target ANSI string. For example CP_UTF8 is UTF-8 code. + \return The target ANSI string. +*/ +inline std::string w2a(const std::wstring& s, int codepage = 0) +{ + return w2a(s.c_str(), codepage); +} + +//! Convert from ANSI string to UNICODE string, x3::a2w. +/*! + \ingroup _GROUP_UTILFUNC + \param s The source ANSI string to be converted. + \param codepage Code page of the source ANSI string. For example CP_UTF8 is UTF-8 code. + \return UNICODE string +*/ +inline std::wstring a2w(const char* s, int codepage = 0) +{ + std::wstring wstr; + int len = (NULL == s) ? 0 : (int)strlen(s); + + if (len > 0) + { + int wlen = MultiByteToWideChar(codepage, 0, s, len, NULL, 0); + wstr.resize(wlen); + MultiByteToWideChar(codepage, 0, s, len, + const_cast(wstr.data()), wlen); + } + + return wstr; +} + +//! Convert from ANSI string to UNICODE string, x3::a2w. +/*! + \ingroup _GROUP_UTILFUNC + \param s The source ANSI string to be converted. + \param codepage Code page of the source ANSI string. For example CP_UTF8 is UTF-8 code. + \return UNICODE string +*/ +inline std::wstring a2w(const std::string& s, int codepage = 0) +{ + return a2w(s.c_str(), codepage); +} + +inline int compare(const std::string& str1, const std::string& str2, bool bCaseSensitive = true) +{ + if (bCaseSensitive) + return str1.compare(str2); + else + { + std::string lowStr1 = str1; + std::transform(lowStr1.begin(), lowStr1.end(), lowStr1.begin(), tolower); + std::string lowStr2 = str2; + std::transform(lowStr2.begin(), lowStr2.end(), lowStr2.begin(), tolower); + return lowStr1.compare(lowStr2); + } +} + +inline int compare(const std::wstring& str1, const std::wstring& str2, bool bCaseSensitive = true) +{ + if (bCaseSensitive) + return str1.compare(str2); + else + { + std::wstring lowStr1 = str1; + std::transform(lowStr1.begin(), lowStr1.end(), lowStr1.begin(), tolower); + std::wstring lowStr2 = str2; + std::transform(lowStr2.begin(), lowStr2.end(), lowStr2.begin(), tolower); + return lowStr1.compare(lowStr2); + } +} + +#ifdef _UNICODE +inline std::wstring w2t(const wchar_t* s) { return s; } +inline std::wstring w2t(const std::wstring& s) { return s; } +inline std::wstring t2w(const wchar_t* s) { return s; } +inline std::wstring a2t(const char* s) { return w2t(a2w(s)); } +inline std::wstring a2t(const std::string& s) { return w2t(a2w(s)); } +inline std::string t2a(const wchar_t* s) { return w2a(t2w(s)); } +#else +inline std::string w2t(const wchar_t* s) { return w2a(s); } +inline std::string w2t(const std::wstring& s) { return w2a(s); } +inline std::wstring t2w(const char* s) { return a2w(s); } +inline std::string a2t(const char* s) { return std::string(s); } +inline std::string a2t(const std::string& s) { return s; } +inline std::string t2a(const char* s) { return std::string(s); } +#endif + +} +#endif // UTILFUNC_CONVSTR_H_ diff --git a/x3py/interface/core/utilfunc/loadmodule.h b/x3py/interface/core/utilfunc/loadmodule.h new file mode 100644 index 0000000..9a36ce4 --- /dev/null +++ b/x3py/interface/core/utilfunc/loadmodule.h @@ -0,0 +1,91 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef UTILFUNC_LOADDLLHELPER_H_ +#define UTILFUNC_LOADDLLHELPER_H_ + +// If don't need plugininc.h or portability/*.h on Windows: +#if !defined(X3_CORE_PORTABILITY_H) && !defined(x3FreeLibrary) && defined(_WIN32) +#define x3FreeLibrary(h) FreeLibrary(h) +#define x3LoadLibrary(f) LoadLibraryExA(f, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) +#endif + +namespace x3 { + +class LoadModuleHelper +{ +public: + LoadModuleHelper(const char* filename = NULL, + HMODULE basemod = NULL, HMODULE* assign = NULL) + : _hmod(NULL), _assign(assign), _loadnew(false) + { + if (filename) + load(filename, basemod); + } + + ~LoadModuleHelper() + { + unload(); + } + + void unload() + { + if (_hmod) + { + if (_loadnew) + x3FreeLibrary(_hmod); + _hmod = NULL; + + if (_assign) + *_assign = NULL; + } + } + + bool load(const char* filename, HMODULE basemod = NULL, const char* folder = "") + { + unload(); + + _hmod = GetModuleHandleA(PathFindFileNameA(filename)); + _loadnew = !_hmod; + + if (!_hmod) + { + char fullname[MAX_PATH] = ""; + + if (PathIsRelativeA(filename)) + { + GetModuleFileNameA(basemod, fullname, MAX_PATH); + PathRemoveFileSpecA(fullname); + PathAppendA(fullname, folder); + PathAppendA(fullname, filename); + _hmod = x3LoadLibrary(fullname); + } + if (!_hmod) + _hmod = x3LoadLibrary(filename); + if (!_hmod) + _hmod = x3LoadLibrary(PathFindFileNameA(filename)); + } + if (_assign) + { + *_assign = _hmod; + } + + return _hmod != NULL; + } + + HMODULE getModule() const + { + return _hmod; + } + + PROC getFunc(const char* name) const + { + return _hmod ? GetProcAddress(_hmod, name) : NULL; + } + +private: + HMODULE _hmod; + HMODULE* _assign; + bool _loadnew; +}; + +} // x3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/utilfunc/lockcount.h b/x3py/interface/core/utilfunc/lockcount.h new file mode 100644 index 0000000..258b52e --- /dev/null +++ b/x3py/interface/core/utilfunc/lockcount.h @@ -0,0 +1,53 @@ +/*! \file lockcount.h +* \brief Define helper class to auto increment and decrement: x3::LockCount + * \author Zhang Yungui, X3 C++ PluginFramework + * \date 2010.5.19 + */ +#ifndef X3_UTILFUNC_LOCKCOUNT_H_ +#define X3_UTILFUNC_LOCKCOUNT_H_ + +namespace x3 { + +//! Helper class to auto increment and decrement. +/*! Use this to declare local variable in functions, + then counter will be auto decreased (--counter;) when leave from the function. + So you can check the counter with initial value to known some status. + \ingroup _GROUP_UTILFUNC +*/ +class LockCount +{ +public: + //! Auto add counter. + /*! + \param p address of counter, the initial value of counter is usually zero. + */ + LockCount(long* p) : m_count(p) + { + InterlockedIncrement(m_count); + } + + //! Auto decrease counter. + ~LockCount() + { + Unlock(); + } + + //! Auto decrease counter. + void Unlock() + { + if (m_count) + { + InterlockedDecrement(m_count); + m_count = NULL; + } + } + +private: + LockCount(const LockCount&); + void operator=(const LockCount&); + + long* m_count; +}; + +} // x3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/utilfunc/lockrw.h b/x3py/interface/core/utilfunc/lockrw.h new file mode 100644 index 0000000..53dd954 --- /dev/null +++ b/x3py/interface/core/utilfunc/lockrw.h @@ -0,0 +1,78 @@ +#ifndef X3_UTILFUNC_LOCKRW_H_ +#define X3_UTILFUNC_LOCKRW_H_ + +namespace x3 { + +class LockRW +{ +public: + struct Data { + long reader; + long writter; + Data() : reader(0), writter(0) {} + }; + + LockRW(Data& data, bool forWrite = false) : _data(data), _type(0) + { + if (forWrite) + { + if (0 == _data.reader && 0 == _data.writter) + { + if (1 == InterlockedIncrement(&_data.writter)) + _type = 2; + else + InterlockedDecrement(&_data.writter); + } + } + if (0 == _type) + { + if (0 == _data.writter) + { + InterlockedIncrement(&_data.reader); + if (0 == _data.writter) + _type = 1; + else + InterlockedDecrement(&_data.reader); + } + } + } + + ~LockRW() + { + free(); + } + + void free() + { + if (1 == _type) + InterlockedDecrement(&_data.reader); + else if (2 == _type) + InterlockedDecrement(&_data.writter); + _type = 0; + } + + bool canRead() const + { + return _type > 0; + } + + bool canWrite() const + { + return 2 == _type; + } + +private: + LockRW(const LockRW&); + LockRW& operator=(const LockRW&); + + Data& _data; + int _type; +}; + +template +struct LockRW_ : public T { + mutable LockRW::Data locker; +}; + +} // x3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/utilfunc/readints.h b/x3py/interface/core/utilfunc/readints.h new file mode 100644 index 0000000..37dbb80 --- /dev/null +++ b/x3py/interface/core/utilfunc/readints.h @@ -0,0 +1,113 @@ +/*! \file readints.h + * \brief Define functions splitting numbers from a string: ReadInts ReadDoubleArray + * \author Zhang Yungui, X3 C++ PluginFramework + * \date 2010.10.22 + */ +#ifndef UTILFUNC_READINTS_H_ +#define UTILFUNC_READINTS_H_ + +namespace x3 { + +//! Check if a character is element of integer number. +/*! + \param c a character to check. + \param signchar true if integer numbers can have plus or minus sign. + \return the character is element of integer number or not. +*/ +inline bool IsIntChar(wchar_t c, bool signchar = false) +{ + return iswdigit(c) || (signchar && (L'+' == c || L'-' == c)); +} + +//! splitting integer numbers from a string. +/*! + \ingroup _GROUP_UTILFUNC + \param[in] str a string which contains numbers separated by punctuation or spaces. + \param[out] arr the buffer which will be filled with numbers. + \param[in] size maximum count of numbers in the buffer 'arr'. + \param[in] signchar true if integer numbers can have plus or minus sign. + \return count of numbers filled in the buffer. + \see IsIntChar, ReadDoubleArray +*/ +template inline +long ReadInts(const wchar_t* str, IntType* arr, long size, bool signchar = false) +{ + if (NULL == str) + { + return 0; + } + + int i, j, count; + wchar_t buf[13]; + + for (i = 0, count = 0; str[i] != 0 && count < size; ) + { + while (str[i] != 0 && !IsIntChar(str[i], signchar)) + { + i++; + } + for (j = i; IsIntChar(str[j], signchar); j++) + { + } + if (j > i) + { + int mincnt = _countof(buf); + mincnt = mincnt < (1 + j - i) ? mincnt : (1 + j - i); + wcsncpy_s(buf, _countof(buf), str + i, mincnt); + arr[count++] = static_cast(wcstol(buf, NULL, 10)); + } + i = j; + } + + return count; +} + +//! Check if a character is element of floating point number. +inline bool IsDblChar(wchar_t c) +{ + return iswdigit(c) || L'+' == c || L'-' == c + || L'.' == c || L'E' == c || L'e' == c; +} + +//! splitting floating point numbers from a string. +/*! + \ingroup _GROUP_UTILFUNC + \param[in] str a string which contains numbers separated by punctuation or spaces. + \param[out] arr the buffer which will be filled with numbers. + \param[in] size maximum count of numbers in the buffer 'arr'. + \return count of numbers filled in the buffer. + \see IsDblChar, ReadInts +*/ +inline long ReadDoubleArray(const wchar_t* str, double* arr, long size) +{ + if (NULL == str) + { + return 0; + } + + int i, j, count; + wchar_t buf[32]; + wchar_t* endptr; + + for (i = 0, count = 0; str[i] != 0 && count < size; ) + { + while (str[i] != 0 && !IsDblChar(str[i])) + { + i++; + } + for (j = i; IsDblChar(str[j]); j++) + { + } + if (j > i) + { + wcsncpy_s(buf, _countof(buf), str + i, 32 < 1 + j - i ? 32 : 1 + j - i); + arr[count++] = wcstod(buf, &endptr); + } + i = j; + } + + return count; +} + +} // x3 +#endif // UTILFUNC_READINTS_H_ diff --git a/x3py/interface/core/utilfunc/roundstr.h b/x3py/interface/core/utilfunc/roundstr.h new file mode 100644 index 0000000..b990c76 --- /dev/null +++ b/x3py/interface/core/utilfunc/roundstr.h @@ -0,0 +1,42 @@ +//! \file roundstr.h +//! \brief Define the function converting and round float-pointing number to string: RoundStr + +#ifndef UTILFUNC_ROUNDSTR_H_ +#define UTILFUNC_ROUNDSTR_H_ + +#include + +namespace x3 { + +//! Returns a numeric string, rounded to the specified precision. +/*! + \ingroup _GROUP_UTILFUNC + \param value float-pointing number to be rounded. + \param decimal a positive number thar value is rounded to the number of decimal places. + \return a numeric string whose zero digits ('0') after number point will be removed. +*/ +inline std::wstring RoundStr(double value, int decimal = 4) +{ + wchar_t buf[65] = { 0 }; + + wchar_t fmt[] = L"%.2lf"; + if (decimal < 1) decimal = 1; + if (decimal > 5) decimal = 5; + fmt[2] = (wchar_t)(L'0' + decimal); + swprintf_s(buf, 65, fmt, value); + + wchar_t* p = wcschr(buf, L'.'); + if (p != NULL) + { + int i = decimal; + for (; i > 0 && p[i] == L'0'; i--) + p[i] = 0; + if (p[i] == L'.') + p[i] = 0; + } + + return buf; +} + +} // x3 +#endif // UTILFUNC_ROUNDSTR_H_ diff --git a/x3py/interface/core/utilfunc/safecall.h b/x3py/interface/core/utilfunc/safecall.h new file mode 100644 index 0000000..db71dd0 --- /dev/null +++ b/x3py/interface/core/utilfunc/safecall.h @@ -0,0 +1,58 @@ +//! \file safecall.h +//! \brief Define functions to call pointer safely. + +#ifndef __APPCORE_SAFECALL_H +#define __APPCORE_SAFECALL_H + +// Validate before call function of pointer, "v" is default return value +#ifndef SafeCall +#define SafeCall(p, f) if (p) p->f +#define SafeCallIf(p, f, v) ((p) ? (p->f) : (v)) +#define WndSafeCall(p, f) if (p && ::IsWindow(p->GetSafeHwnd())) p->f +#endif // SafeCall + +namespace x3 { + +//! Delete pointer object. +/*! + \ingroup _GROUP_UTILFUNC + \param p pointer object created using 'new'. +*/ +template +void SafeDelete(T*& p) +{ + if (p != NULL) + delete p; + p = NULL; + *(&p) = NULL; +} + +//! Delete pointer array object. +/*! + \ingroup _GROUP_UTILFUNC + \param p pointer array object created using 'new []'. +*/ +template +void SafeDeleteArray(T*& p) +{ + if (p != NULL) + delete []p; + p = NULL; +} + +//! Delete all elements in a container. +/*! + \ingroup _GROUP_UTILFUNC + \param container STL container variable (vector, list, map). eg: " vector arr; " +*/ +template +void DeletePtrInContainer(CONTAINER& container) +{ + typename CONTAINER::iterator it = container.begin(); + for(; it != container.end(); ++it) + SafeDelete(*it); + container.resize(0); +} + +} // x3 +#endif // __APPCORE_SAFECALL_H diff --git a/x3py/interface/core/utilfunc/scanfiles.h b/x3py/interface/core/utilfunc/scanfiles.h new file mode 100644 index 0000000..2851b07 --- /dev/null +++ b/x3py/interface/core/utilfunc/scanfiles.h @@ -0,0 +1,102 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_UTILFUNC_SCANDIR_H +#define X3_UTILFUNC_SCANDIR_H + +#ifndef _WIN32 +#include +#include +#include +#endif + +namespace x3 { + +inline int scanfiles(bool (*filter)(const char* filename, const char* ext), + const char* path, bool recursive) +{ + int count = 0; + char filename[MAX_PATH]; + bool cancel = false; + +#ifdef _WIN32 + lstrcpynA(filename, path, MAX_PATH); + PathAppendA(filename, "*.*"); + + WIN32_FIND_DATAA fd; + HANDLE hfind = ::FindFirstFileA(filename, &fd); + BOOL loop = (hfind != INVALID_HANDLE_VALUE); + + for (; loop && !cancel; loop = ::FindNextFileA(hfind, &fd)) + { + if (fd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) + { + } + else if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (fd.cFileName[0] != '.') + { + lstrcpynA(filename, path, MAX_PATH); + PathAppendA(filename, fd.cFileName); + PathAddBackslashA(filename); + + cancel = !filter(filename, ""); + if (recursive && !cancel) + { + count += scanfiles(filter, filename, recursive); + } + } + } + else + { + lstrcpynA(filename, path, MAX_PATH); + PathAppendA(filename, fd.cFileName); + cancel = !filter(filename, PathFindExtensionA(filename)); + count++; + } + } + + ::FindClose(hfind); +#else + std::vector dirs; + struct dirent *dp; + DIR *dirp; + + dirp = opendir(path); + if (dirp) + { + while (!cancel && (dp = readdir(dirp)) != NULL) + { + if (DT_DIR == dp->d_type && dp->d_name[0] != '.') + { + dirs.push_back(dp->d_name); + } + else if (DT_REG == dp->d_type) + { + strncpy(filename, path, MAX_PATH); + PathAppendA(filename, dp->d_name); + cancel = !filter(filename, ""); + count++; + } + } + closedir(dirp); + } + + std::vector::const_iterator it = dirs.begin(); + for (; it != dirs.end() && !cancel; ++it) + { + strncpy(filename, path, MAX_PATH); + PathAppendA(filename, it->c_str()); + PathAddBackslashA(filename); + + cancel = !filter(filename, PathFindExtensionA(filename)); + if (recursive && !cancel) + { + count += scanfiles(filter, filename, recursive); + } + } +#endif + + return count; +} + +} // x3 +#endif \ No newline at end of file diff --git a/x3py/interface/core/utilfunc/syserrstr.h b/x3py/interface/core/utilfunc/syserrstr.h new file mode 100644 index 0000000..13824aa --- /dev/null +++ b/x3py/interface/core/utilfunc/syserrstr.h @@ -0,0 +1,48 @@ +//! \file syserrstr.h +//! \brief Define a function to obtains error message strings: GetSystemErrorString. + +#ifndef UTILFUNC_SYSERRSTR_H_ +#define UTILFUNC_SYSERRSTR_H_ + +#include + +namespace x3 { + +//! Obtains error message strings for a error code. +/*! + \ingroup _GROUP_UTILFUNC + \param errorcode the error code returned by GetLastError or HRESULT value. + \return error message strings. +*/ +inline std::wstring GetSystemErrorString(unsigned long errorcode) +{ + std::wstring retstr; + wchar_t buf[21] = { 0 }; + + if (errorcode != 0) + { +#ifdef FormatMessage + wchar_t* p = NULL; + + ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, errorcode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (wchar_t*)&p, 0, NULL); + + if (p != NULL) + { + retstr = p; + ::LocalFree((HLOCAL)p); + } +#endif + + // define _NEED_STDIO before include PluginInc.h for vc6 or gcc. + swprintf_s(buf, _countof(buf), L"[0x%x]", errorcode); + retstr = buf + retstr; + } + + return retstr; +} + +} // x3 +#endif // UTILFUNC_SYSERRSTR_H_ diff --git a/x3py/interface/core/utilfunc/vecfunc.h b/x3py/interface/core/utilfunc/vecfunc.h new file mode 100644 index 0000000..55f14fc --- /dev/null +++ b/x3py/interface/core/utilfunc/vecfunc.h @@ -0,0 +1,143 @@ +//! \file vecfunc.h +//! \brief Define functions of STL container and include frequently-used STL files. + +#ifndef __STL_VECTOR_FUNCTIONS_H +#define __STL_VECTOR_FUNCTIONS_H + +#ifdef _MSC_VER // hide warnings +#pragma warning(disable:4710) // inline function not expanded +#pragma warning(disable:4786) // identifier was truncated +#pragma warning (push, 3) +#pragma warning(disable:4018) // signed/unsigned mismatch +#pragma warning(disable:4702) // unreachable code +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _MSC_VER // hide warnings +#pragma warning (pop) +#endif + +namespace x3 { + +#ifdef __AFX_H__ +//! Converts safely from CString variable to std::wstring, avoid null address problem. +inline std::wstring towstr(const CString& str) +{ + return str.IsEmpty() ? L"" : (LPCTSTR)str; +} +#endif + +//! Removes an element that match a condition expression in a container. +/*! + \ingroup _GROUP_UTILFUNC + \param arr STL container variable (vector, list, map). eg: " vector arr; " + \param _P The condition expression for matching elements. eg: " std::bind2nd(std::equal_to(), pObj) " + \return the element is removed or not. + \see erase_value, find_if +*/ +template inline +bool erase_if(_Ta& arr, _Pr _P) +{ + typename _Ta::iterator it = std::find_if(arr.begin(), arr.end(), _P); + bool b = (it != arr.end()); + + if (b) + { + arr.erase(it); + } + + return b; +}; + +//! Removes an element that match a element value in a container. +/*! + \ingroup _GROUP_UTILFUNC + \param arr STL container variable (vector, list, map). eg: " vector arr; " + \param p The element value for matching. It's type is same as the element type of 'arr'. eg: " Ix_xxx* pObj" + \return the element is removed or not. + \see erase_if, find_value +*/ +template inline +bool erase_value(_Ta& arr, _Tp& p) +{ + return erase_if(arr, std::bind2nd(std::equal_to<_Tp>(), p)); +} + +//! Finds the position index of an element that match a condition expression in a container. +/*! + \ingroup _GROUP_UTILFUNC + \param arr STL vector variable. eg: " vector arr; " + \param _P The condition expression for matching elements. eg: " std::bind2nd(std::equal_to(), pObj) " + \return the position index of an element, or -1 if not found. + \see find_value, has_value +*/ +template inline +long find_if(const _Ta& arr, _Pr _P) +{ + typename _Ta::const_iterator it = std::find_if(arr.begin(), arr.end(), _P); + return (it != arr.end()) ? (long)(it - arr.begin()) : -1; +} + +//! Finds the position index of an element that match a element value in a container. +/*! + \ingroup _GROUP_UTILFUNC + \param arr STL container variable (vector, list, map). eg: " vector arr; " + \param p The element value for matching. It's type is same as the element type of 'arr'. eg: " Ix_xxx* pObj" + \return the position index of an element, or -1 if not found. + \see has_value, find_if +*/ +template inline +long find_value(const _Ta& arr, const _Tp& p) +{ + return find_if(arr, std::bind2nd(std::equal_to<_Tp>(), p)); +} + +//! Checks whether a container has an element that match a element value or not. +/*! + \ingroup _GROUP_UTILFUNC + \param arr STL container variable (vector, list, map). eg: " vector arr; " + \param p The element value for matching. It's type is same as the element type of 'arr'. eg: " Ix_xxx* pObj" + \return true if the container has the element. + \see find_value, find_if +*/ +template inline +bool has_value(const _Ta& arr, const _Tp& p) +{ + typename _Ta::const_iterator it = std::find_if(arr.begin(), arr.end(), + std::bind2nd(std::equal_to<_Tp>(), p)); + return it != arr.end(); +} + +//! Returns element count of a container. +/*! + \ingroup _GROUP_UTILFUNC + \param arr STL container variable (vector, list, map). + \return element count. +*/ +template inline +int GetSize(const _Ta& arr) +{ + return static_cast(arr.size()); +} + +//! Checks a position index is in range or out of range of a container. +/*! + \ingroup _GROUP_UTILFUNC + \param arr STL vector variable. eg: " vector arr; " + \param index The position index of the element. + \return true if the position index is in range of the container. +*/ +template inline +bool IsValidIndexOf(const _Ta& arr, int index) +{ + return index >= 0 && index < static_cast(arr.size()); +} + +} // x3 +#endif // __STL_VECTOR_FUNCTIONS_H diff --git a/x3py/source/Makefile b/x3py/source/Makefile new file mode 100644 index 0000000..423ef93 --- /dev/null +++ b/x3py/source/Makefile @@ -0,0 +1,30 @@ +# Makefile of packages + +ROOTDIR =.. +include $(ROOTDIR)/config.mk + +SUBDIRS =$(filter-out public, $(subst /,,$(dir $(wildcard */)))) +SWIGSUBDIRS =$(addsuffix .swig, $(SUBDIRS)) +CLEANSUBDIRS =$(addsuffix .clean, $(SUBDIRS)) + +.PHONY: $(SUBDIRS) $(SWIGSUBDIRS) swig +all: $(SUBDIRS) + +$(SUBDIRS): + @ ! test -e $@/Makefile || $(MAKE) -C $@ + +swig: $(SWIGSUBDIRS) + +$(SWIGSUBDIRS): + @$(MAKE) -C $(basename $@) swig + +clean: $(CLEANSUBDIRS) +ifdef touch + touch -c * +endif + +$(CLEANSUBDIRS): + @!(test -e $(basename $@)/Makefile) || $(MAKE) -C $(basename $@) clean +ifdef touch + touch -c $(basename $@)/* +endif diff --git a/x3py/source/core/Makefile b/x3py/source/core/Makefile new file mode 100644 index 0000000..e5f636b --- /dev/null +++ b/x3py/source/core/Makefile @@ -0,0 +1,27 @@ +# Makefile of projects in this package + +ROOTDIR =../.. +include $(ROOTDIR)/config.mk + +SUBDIRS =$(filter-out public, $(subst /,,$(dir $(wildcard */)))) +SWIGSUBDIRS =$(addsuffix .swig, $(SUBDIRS)) +CLEANSUBDIRS =$(addsuffix .clean, $(SUBDIRS)) + +.PHONY: $(SUBDIRS) $(SWIGSUBDIRS) swig +all: $(SUBDIRS) + +$(SUBDIRS): + @echo --Making project $@... + @ ! test -e $@/Makefile || $(MAKE) -C $@ + +swig: $(SWIGSUBDIRS) + +$(SWIGSUBDIRS): + @!(test -d $(basename $@)/swig) || $(MAKE) -C $(basename $@)/swig swig + @!(test -e $(basename $@)/$(basename $@).i) || $(MAKE) -C $(basename $@) swig + +clean: $(CLEANSUBDIRS) + +$(CLEANSUBDIRS): + @!(test -e $(basename $@)/Makefile) || $(MAKE) -C $(basename $@) clean + @!(test -d $(basename $@)/swig) || $(MAKE) -C $(basename $@)/swig clean diff --git a/x3py/source/core/x3manager/Makefile b/x3py/source/core/x3manager/Makefile new file mode 100644 index 0000000..d40081f --- /dev/null +++ b/x3py/source/core/x3manager/Makefile @@ -0,0 +1,10 @@ +ROOTDIR =../../.. +PROJNAME =x3manager + +include $(ROOTDIR)/config.mk + +ifdef IS_WIN +LIBS += $(LIBFLAG)ole32$(LIBEND) +endif + +include $(SRCPUB_DIR)/mk/Makefile.pln diff --git a/x3py/source/core/x3manager/module.cpp b/x3py/source/core/x3manager/module.cpp new file mode 100644 index 0000000..31c3028 --- /dev/null +++ b/x3py/source/core/x3manager/module.cpp @@ -0,0 +1,208 @@ +// x3py framework: https://github.com/rhcad/x3py +#include +#include +#define X3_EXCLUDE_CREATEOBJECT +#include + +#include +#include +#include +#include + +#include "plugins.h" +#include "workpath.h" + + +BEGIN_NAMESPACE_X3 + +class CManager : public CPlugins, public CWorkPath +{ + X3BEGIN_CLASS_DECLARE(CManager, clsidManager) + X3USE_INTERFACE_ENTRY(CPlugins) + X3USE_INTERFACE_ENTRY(CWorkPath) + X3END_CLASS_DECLARE() +protected: + CManager() {} + +private: + virtual int loadExtraPlugins(const char* folder); + virtual int unloadExtraPlugins(); +}; + +static std::vector _plns; +static long _loading = 0; + +XBEGIN_DEFINE_MODULE() + XDEFINE_CLASSMAP_ENTRY_Singleton(CManager) +XEND_DEFINE_MODULE_DLL() + +OUTAPI bool x3InitializePlugin() +{ + return true; +} + +OUTAPI void x3UninitializePlugin() +{ + Object reg(clsidManager); + SafeCall(reg, unloadExtraPlugins()); +} + +OUTAPI bool x3RegisterPlugin(Creator creator, HMODULE hmod, const char** clsids) +{ + bool needInit = (_loading == 0); + Object reg(clsidManager); + + SafeCall(reg, registerPlugin(creator, hmod, clsids)); + + return needInit; +} + +OUTAPI bool x3UnregisterPlugin(Creator creator) +{ + bool needFree = (_loading == 0); + Object reg(clsidManager); + + if (reg && creator) + reg->unregisterPlugin(creator); + + return needFree; +} + +OUTAPI bool x3CreateObject(const char* clsid, long iid, IObject** p) +{ + if (x3InternalCreate(clsid, iid, p)) + return true; + Object reg(clsidManager); + return reg && reg->createFromOthers(clsid, iid, p); +} + +OUTAPI bool x3RegisterObserver(const char* type, PROC handler, Creator creator) +{ + Object reg(clsidManager); + return reg && reg->registerObserver(type, handler, creator); +} + +OUTAPI bool x3RegisterObserverObject(const char* type, ObserverObject* obj, + ON_EVENT handler, Creator creator) +{ + Object reg(clsidManager); + return reg && reg->registerObserver(type, obj, handler, creator); +} + +OUTAPI void x3UnregisterObserverObject(ObserverObject* obj) +{ + Object reg(clsidManager); + if (reg && obj) + reg->unregisterObserver(obj); +} + +OUTAPI int x3FireEvent(const char* type, EventDispatcher dispatcher, void* data) +{ + Object reg(clsidManager); + return SafeCallIf(reg, fireEvent(type, dispatcher, data), 0); +} + +OUTAPI int x3FireObjectEvent(const char* type, ObjectEventDispatcher dispatcher, void* data) +{ + Object reg(clsidManager); + return SafeCallIf(reg, fireEvent(type, dispatcher, data), 0); +} + +#ifndef _WIN32 +OUTAPI HMODULE unixFindModule(const char* filename) +{ + Object reg(clsidManager); + return SafeCallIf(reg, findModuleByFileName(filename), NULL); +} +#endif // UNIX + +static bool loadfilter(const char* filename, const char* ext) +{ + if (_stricmp(ext, ".pln") == 0 + && GetModuleHandleA(PathFindFileNameA(filename)) == NULL) + { + HMODULE hmod = x3LoadLibrary(filename); + + if (hmod && GetProcAddress(hmod, "x3InitializePlugin")) + _plns.push_back(hmod); + else if (hmod) + x3FreeLibrary(hmod); + } + return true; +} + +int CManager::loadExtraPlugins(const char* folder) +{ + char path[MAX_PATH]; + LockCount locker(&_loading); + int from = (int)_plns.size(); + int ret = 0; + + GetModuleFileNameA(getModuleHandle(), path, MAX_PATH); + PathRemoveFileSpecA(path); + PathRemoveFileSpecA(path); + PathAppendA(path, folder); + + x3::scanfiles(loadfilter, path, true); + locker.Unlock(); + + for (int i = from; i < (int)_plns.size(); i++) + { + typedef bool (*INITF)(); + INITF init = (INITF)GetProcAddress(_plns[i], "x3InitializePlugin"); + + if (init && !init()) + { + x3FreeLibrary(_plns[i]); + _plns[i] = NULL; + } + else + { + ret++; + } + } + + return ret; +} + +int CManager::unloadExtraPlugins() +{ + LockCount locker(&_loading); + int count = 0; + + std::vector::reverse_iterator it = _plns.rbegin(); + for (; it != _plns.rend(); it++) + { + typedef bool (*UF)(); + UF f = (UF)GetProcAddress(*it, "x3UninitializePlugin"); + if (f) f(); + } + + while (!_plns.empty()) + { + HMODULE hmod = _plns.back(); + _plns.pop_back(); + + if (hmod) + { + x3FreeLibrary(hmod); + count++; + } + } + + return count; +} + +OUTAPI int x3LoadPlugins(const char* folder) +{ + Object reg(clsidManager); + return SafeCallIf(reg, loadExtraPlugins(folder), 0); +} + +OUTAPI int x3UnloadPlugins() +{ + Object reg(clsidManager); + return SafeCallIf(reg, unloadExtraPlugins(), 0); +} + +END_NAMESPACE_X3 diff --git a/x3py/source/core/x3manager/plugins.cpp b/x3py/source/core/x3manager/plugins.cpp new file mode 100644 index 0000000..7087b9f --- /dev/null +++ b/x3py/source/core/x3manager/plugins.cpp @@ -0,0 +1,346 @@ +// x3py framework: https://github.com/rhcad/x3py +#include +#include +#include "plugins.h" + +BEGIN_NAMESPACE_X3 + +CPlugins::CPlugins() +{ +} + +CPlugins::~CPlugins() +{ +} + +int CPlugins::getPluginCount() const +{ + LockRW locker(_plugins.locker); + return locker.canRead() ? (1 + GetSize(_plugins)) : 1; +} + +void CPlugins::getPluginFiles(std::vector& files) const +{ + char filename[MAX_PATH] = { 0 }; + + files.clear(); + GetModuleFileNameA(getModuleHandle(), filename, MAX_PATH); + files.push_back(filename); + + LockRW locker(_plugins.locker); + if (locker.canRead()) + { + for (std::vector::const_iterator it = _plugins.begin(); + it != _plugins.end(); ++it) + { + GetModuleFileNameA(it->second, filename, MAX_PATH); + files.push_back(filename); + } + } +} + +bool CPlugins::registerPlugin(Creator creator, HMODULE hmod, const char** clsids) +{ + bool needInit = true; + LockRW locker(_plugins.locker, true); + + if (locker.canWrite() && find_value(_plugins, Plugin(creator, hmod)) < 0) + { + _plugins.push_back(Plugin(creator, hmod)); + + LockRW lockcls(_clsmap.locker, true); + for (; *clsids && lockcls.canWrite(); clsids++) + { + _clsmap.insert(CreatorPair(*clsids, creator)); +#ifdef USE_VECTOR_CLSID + _clsids.push_back(*clsids); +#endif + } + } + + return needInit; +} + +void CPlugins::unregisterPlugin(Creator creator) +{ + LockRW locker(_plugins.locker, true); + if (locker.canWrite()) + { + for (std::vector::iterator it = _plugins.begin(); + it != _plugins.end(); ++it) + { + if (it->first == creator) + { + _plugins.erase(it); + break; + } + } + } + + LockRW lockcls(_clsmap.locker, true); + if (lockcls.canWrite()) + { + CreatorMap::iterator it = _clsmap.begin(); + while (it != _clsmap.end()) + { + if (it->second == creator) + { +#ifdef USE_VECTOR_CLSID + for (std::vector::iterator pit = _clsids.begin(); pit != _clsids.end(); pit++) + { + if (compare(it->first, *pit, false) == 0){ + _clsids.erase(pit); + break; + } + } +#endif + _clsmap.erase(it); + it = _clsmap.begin(); + } + else + { + ++it; + } + } + } + + LockRW lockobserver(_observers.locker, true); + if (lockobserver.canRead()) + { + for (MAP_IT it = _observers.begin(); it != _observers.end(); ) + { + if (it->second.creator == creator) + { + if (lockobserver.canWrite()) + { + _observers.erase(it); + it = _observers.begin(); + } + else + { + it->second = ObserverItem(); + ++it; + } + } + else + { + ++it; + } + } + } +} + +void CPlugins::unregisterObserver(ObserverObject* obj) +{ + LockRW locker(_observers.locker, true); + + if (!locker.canRead()) + { + return; + } + for (MAP_IT it = _observers.begin(); it != _observers.end(); ) + { + if (it->second.obj == obj) + { + if (locker.canWrite()) + { + _observers.erase(it); + it = _observers.begin(); + } + else + { + it->second.obj = NULL; + ++it; + } + } + else + { + ++it; + } + } +} + +Creator CPlugins::findPluginByClassID(const char* clsid) const +{ + LockRW locker(_clsmap.locker); + Creator ret = NULL; + + if (locker.canRead()) + { + CreatorMap::const_iterator it = _clsmap.find(clsid); + ret = (it != _clsmap.end()) ? it->second : NULL; + } + + return ret; +} + +bool CPlugins::createFromOthers(const char* clsid, long iid, IObject** p) +{ + Creator creator = findPluginByClassID(clsid); + if (creator && creator(clsid, iid, p)) + { + return true; + } + return false; +} + +bool CPlugins::registerObserver(const char* type, PROC handler, Creator creator) +{ + LockRW locker(_observers.locker, true); + bool ret = type && handler && creator && locker.canWrite(); + + if (ret) + { + ObserverItem item; + item.creator = creator; + item.handler = handler; + item.obj = NULL; + item.objhandler = NULL; + _observers.insert(ObserverPair(type, item)); + } + + return ret; +} + +bool CPlugins::registerObserver(const char* type, ObserverObject* obj, + ON_EVENT handler, Creator creator) +{ + LockRW locker(_observers.locker, true); + bool ret = type && obj && handler && creator && locker.canWrite(); + + if (ret) + { + ObserverItem item; + item.creator = creator; + item.handler = NULL; + item.obj = obj; + item.objhandler = handler; + _observers.insert(ObserverPair(type, item)); + } + + return ret; +} + +int CPlugins::fireEvent(const char* type, EventDispatcher dispatcher, void* data) +{ + LockRW locker(_observers.locker); + std::vector observers; + + if (locker.canRead()) + { + std::pair range (_observers.equal_range(type)); + + for (MAP_IT it = range.first; it != range.second; ++it) + { + if (it->second.handler) + { + observers.push_back(it->second.handler); + } + } + } + locker.free(); + + int count = 0; + std::vector::iterator it = observers.begin(); + + for (; it != observers.end(); ++it) + { + count++; + if (!dispatcher(*it, data)) + break; + } + + return count; +} + +int CPlugins::fireEvent(const char* type, ObjectEventDispatcher dispatcher, void* data) +{ + LockRW locker(_observers.locker); + typedef std::pair Pair; + std::vector observers; + + if (locker.canRead()) + { + std::pair range (_observers.equal_range(type)); + + for (MAP_IT it = range.first; it != range.second; ++it) + { + if (it->second.obj && it->second.objhandler) + { + observers.push_back(Pair(it->second.obj, it->second.objhandler)); + } + } + } + locker.free(); + + int count = 0; + std::vector::iterator it = observers.begin(); + + for (; it != observers.end(); ++it) + { + count++; + if (!dispatcher(it->first, it->second, data)) + break; + } + + return count; +} + +HMODULE CPlugins::findModuleByFileName(const char* filename) +{ + char tmp[MAX_PATH]; + LockRW locker(_plugins.locker); + + if (!locker.canRead()) + { + return NULL; + } + + for (std::vector::const_iterator it = _plugins.begin(); + it != _plugins.end(); ++it) + { + typedef bool (*F)(char*, int); + F f = (F)GetProcAddress(it->second, "_getdlname"); + + if (f && f(tmp, MAX_PATH) && _stricmp(tmp, filename) == 0) + { + return it->second; + } + } + + return NULL; +} + +int CPlugins::getCLSIDCount() const +{ + LockRW locker(_clsmap.locker); + return locker.canRead() ? _clsmap.size() : 0; +} + +const char* CPlugins::getCLSID(int index) +{ + LockRW locker(_clsmap.locker); + const char* ret = NULL; + if (locker.canRead()) + { + if( index>=0 && index<_clsmap.size() ) + { +#ifdef USE_VECTOR_CLSID + return _clsids.at(index).c_str(); +#else + hash_map::iterator it = _clsmap.begin(); + for( int i=0; ifirst.c_str(); + } +#endif + } + } + + return ret; +} + +END_NAMESPACE_X3 diff --git a/x3py/source/core/x3manager/plugins.h b/x3py/source/core/x3manager/plugins.h new file mode 100644 index 0000000..3f0c774 --- /dev/null +++ b/x3py/source/core/x3manager/plugins.h @@ -0,0 +1,104 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_PLUGINS_IMPL_H +#define X3_CORE_PLUGINS_IMPL_H + +#include +#include +#include +#include +#include + +#if !defined(_MSC_VER) || _MSC_VER >= 1700 +#include +#define hash_multimap std::unordered_multimap +#else +#if defined(_MSC_VER) && _MSC_VER > 1200 // VC8/9 + #include + using stdext::hash_multimap; +#else // VC6, GCC or others + #define hash_multimap std::multimap +#endif +#endif + +#define USE_VECTOR_CLSID + +BEGIN_NAMESPACE_X3 + +typedef bool (*EventDispatcher)(PROC handler, void* data); +typedef bool (*ObjectEventDispatcher)(ObserverObject*, ON_EVENT, void* data); +typedef bool (*Creator)(const char*, long, IObject**); + +class IRegister : public IObject +{ + X3DEFINE_IID(IRegister); + virtual bool registerPlugin(Creator creator, HMODULE hmod, const char** clsids) = 0; + virtual void unregisterPlugin(Creator creator) = 0; + virtual bool createFromOthers(const char* clsid, long iid, IObject** p) = 0; + virtual HMODULE findModuleByFileName(const char* filename) = 0; + + virtual bool registerObserver(const char* type, PROC handler, Creator creator) = 0; + virtual bool registerObserver(const char* type, ObserverObject* obj, + ON_EVENT handler, Creator creator) = 0; + virtual void unregisterObserver(ObserverObject* obj) = 0; + virtual int fireEvent(const char* type, EventDispatcher dispatcher, void* data) = 0; + virtual int fireEvent(const char* type, ObjectEventDispatcher dispatcher, void* data) = 0; +}; + +class CPlugins : public IPlugins + , public IRegister +{ + X3BEGIN_CLASS_DECLARE0(CPlugins) + X3DEFINE_INTERFACE_ENTRY(IPlugins) + X3DEFINE_INTERFACE_ENTRY(IRegister) + X3END_CLASS_DECLARE() +protected: + CPlugins(); + virtual ~CPlugins(); + +private: + virtual bool registerPlugin(Creator creator, HMODULE hmod, const char** clsids); + virtual void unregisterPlugin(Creator creator); + virtual bool createFromOthers(const char* clsid, long iid, IObject** p); + virtual HMODULE findModuleByFileName(const char* filename); + + virtual bool registerObserver(const char* type, PROC handler, Creator creator); + virtual bool registerObserver(const char* type, ObserverObject* obj, + ON_EVENT handler, Creator creator); + virtual void unregisterObserver(ObserverObject* obj); + virtual int fireEvent(const char* type, EventDispatcher dispatcher, void* data); + virtual int fireEvent(const char* type, ObjectEventDispatcher dispatcher, void* data); + + virtual int getPluginCount() const; + virtual void getPluginFiles(std::vector& files) const; + virtual Creator findPluginByClassID(const char* clsid) const; + + virtual int getCLSIDCount() const; + virtual const char* getCLSID(int index); + +private: + typedef std::pair Plugin; + typedef hash_multimap CreatorMap; + typedef std::pair CreatorPair; + LockRW_ > _plugins; + LockRW_ _clsmap; +#ifdef USE_VECTOR_CLSID + std::vector _clsids; +#endif + + struct ObserverItem { + Creator creator; + PROC handler; + ObserverObject* obj; + ON_EVENT objhandler; + + ObserverItem() : creator(NULL), handler(NULL), obj(NULL), objhandler(NULL) {} + }; + typedef hash_multimap ObserverMap; + typedef std::pair ObserverPair; + typedef ObserverMap::iterator MAP_IT; + + LockRW_ _observers; +}; + +END_NAMESPACE_X3 +#endif diff --git a/x3py/source/core/x3manager/swig/Makefile b/x3py/source/core/x3manager/swig/Makefile new file mode 100644 index 0000000..f023cf0 --- /dev/null +++ b/x3py/source/core/x3manager/swig/Makefile @@ -0,0 +1,6 @@ +ROOTDIR =../../../.. +PKGNAME =core +PROJNAME =x3manager + +include $(ROOTDIR)/config.mk +include $(SRCPUB_DIR)/swig/Makefile.swig diff --git a/x3py/source/core/x3manager/swig/testx3manager.py b/x3py/source/core/x3manager/swig/testx3manager.py new file mode 100644 index 0000000..a0632b2 --- /dev/null +++ b/x3py/source/core/x3manager/swig/testx3manager.py @@ -0,0 +1,36 @@ +# This example illustrates how multiple C++ plugins can be used from Python. + +from core.x3manager import * +import example.plsimple as A +import example.observerex as B + +a = Plugins("") +if not a.valid(): print("The x3manager plugins is not loaded.") + +print("plugin count: %d" % a.getPluginCount()) + +files = Strings() +a.getPluginFiles(files) +for i,f in enumerate(files): print(" %d. %s" % (i+1,f)) + +print("x3manager.Plugins: %s of %s" % (a.getInterfaceName(), a.getClassName())) + +b = A.Simple(A.clsidSimple) +print("Simple(clsidSimple) ok." if b.valid() else "Simple(clsidSimple) fail.") +if b.valid(): + print("Simple(clsidSimple) ok.") + print("clsidSimple: %s of %s" % (a.getInterfaceName(), a.getClassName())) + +c = AnyObject(b.p()) +if c.valid(): + print("AnyObject(anotherobj.p()) ok.") + print("AnyObject: iid=%d, clsid=%s" % (c.getIID(), c.getClassID())) + +print("---loadExtraPlugins---") +p = Plugins("") +print("plugins loaded: %d" % p.loadExtraPlugins("plugins")) +print("plugin count: %d" % p.getPluginCount()) +p.getPluginFiles(files) +for i,f in enumerate(files): print(" %d. %s" % (i+1,f)) +print("plugins unloaded: %d" % p.unloadExtraPlugins()) +#print(list(files)) diff --git a/x3py/source/core/x3manager/swig/x3manager.i b/x3py/source/core/x3manager/swig/x3manager.i new file mode 100644 index 0000000..a077fd1 --- /dev/null +++ b/x3py/source/core/x3manager/swig/x3manager.i @@ -0,0 +1,20 @@ +%module x3manager +%{ +#ifndef PLUGIN_NAME +#define PLUGIN_NAME "x3manager" +#endif +%} +%include + +%{ +#include +%} + +%include std_vector.i +%include std_string.i +%template(Strings) std::vector; + +%include +%template(Plugins) x3::Object; + +%include diff --git a/x3py/source/core/x3manager/workpath.cpp b/x3py/source/core/x3manager/workpath.cpp new file mode 100644 index 0000000..3cccaba --- /dev/null +++ b/x3py/source/core/x3manager/workpath.cpp @@ -0,0 +1,163 @@ +// x3py framework: https://github.com/rhcad/x3py +#include +#include "workpath.h" +#include + +#ifdef WINOLEAPI_ +#pragma comment(lib, "Ole32.lib") +#endif + +BEGIN_NAMESPACE_X3 + +static inline void GetBasePath(char* path) +{ + GetModuleFileNameA(getModuleHandle(), path, MAX_PATH); + PathRemoveFileSpecA(path); + if (_stricmp("plugins", PathFindFileNameA(path)) == 0) + PathRemoveFileSpecA(path); +} + +std::wstring CWorkPath::getWorkPath() +{ + if (m_path.empty()) + { + /*if (isVistaDisk()) + { + m_path = getLocalAppDataPath(L"x3"); + } + else*/ + { + char path[MAX_PATH] = { 0 }; + GetBasePath(path); + PathAddBackslashA(path); + m_path = a2w(path); + } + } + return m_path; +} + +void CWorkPath::setWorkPath(const std::wstring& path) +{ + m_path = path; + if (path.size() > 2 + && *path.rbegin() != L'/' && *path.rbegin() != L'\\') + { + m_path += L'\\'; + } +} + +std::wstring CWorkPath::getConfigPath(const wchar_t* subfolder) +{ + char path[MAX_PATH] = { 0 }; + + GetBasePath(path); + PathAppendA(path, "config"); + if (subfolder && *subfolder) + PathAppendA(path, w2a(subfolder).c_str()); + PathAddBackslashA(path); + + return a2w(path); +} + +std::wstring CWorkPath::getLocalAppDataPath(const wchar_t* company) +{ + char path[MAX_PATH] = { 0 }; + + if (getLocalAppDataPath_(path)) + { + char appname[MAX_PATH]; + GetModuleFileNameA(NULL, appname, MAX_PATH); + + if (company) + PathAppendA(path, w2a(company).c_str()); + PathAppendA(path, PathFindFileNameA(appname)); + PathRenameExtensionA(path, ""); + PathAddBackslashA(path); + } + else + { + GetBasePath(path); + PathAddBackslashA(path); + } + + return a2w(path); +} + +std::wstring CWorkPath::getTranslationsPath(const wchar_t* subfolder) +{ + char code[4] = "chs"; + char path[MAX_PATH] = { 0 }; + +#ifdef _WIN32 + typedef LANGID (WINAPI*PFNGETUSERDEFAULTUILANGUAGE)(); + PFNGETUSERDEFAULTUILANGUAGE pfnGetLang; + + pfnGetLang = (PFNGETUSERDEFAULTUILANGUAGE)::GetProcAddress( + ::GetModuleHandleA("kernel32.dll"), "GetUserDefaultUILanguage"); + if (pfnGetLang != NULL) + { + LANGID langid = pfnGetLang(); + ::GetLocaleInfoA(langid, LOCALE_SABBREVLANGNAME, code, 4); + } +#endif + + GetBasePath(path); + PathAppendA(path, "translations"); + PathAppendA(path, code); + PathAddBackslashA(path); + if (subfolder && *subfolder) + PathAppendA(path, w2a(subfolder).c_str()); + + return a2w(path); +} + +bool CWorkPath::isVistaDisk() +{ + bool ret = false; +#ifdef WINOLEAPI_ + OSVERSIONINFO osvi = { sizeof(OSVERSIONINFO) }; + char winpath[MAX_PATH], exepath[MAX_PATH]; + + if (GetVersionEx(&osvi) && osvi.dwMajorVersion >= 6) + { + GetSystemDirectoryA(winpath, MAX_PATH); + GetModuleFileNameA(getModuleHandle(), exepath, MAX_PATH); + ret = (_strnicmp(winpath, exepath, 2) == 0); + } +#endif + return ret; +} + +bool CWorkPath::getLocalAppDataPath_(char* path) +{ + bool ret = false; +#ifdef WINOLEAPI_ + // FOLDERID_LocalAppDataGUID {F1B32785-6FBA-4FCF-9D55-7B8E7F157091} + const GUID uuidLocalAppData = {0xF1B32785,0x6FBA,0x4FCF, + {0x9D,0x55,0x7B,0x8E,0x7F,0x15,0x70,0x91}}; + + typedef HRESULT (STDAPICALLTYPE *PFNGET)(REFGUID, DWORD, HANDLE, PWSTR*); + HMODULE hdll = LoadLibraryA("SHELL32.DLL"); + + if (hdll != NULL) + { + PWSTR shpath = NULL; + PFNGET pfn = (PFNGET)GetProcAddress(hdll, "SHGetKnownFolderPath"); + + if (pfn != NULL) + { + pfn(uuidLocalAppData, 0, NULL, &shpath); + } + if (shpath != NULL) + { + strcpy_s(path, MAX_PATH, w2a(shpath).c_str()); + ret = (*path != 0); + CoTaskMemFree(shpath); + } + FreeLibrary(hdll); + } +#endif + return ret; +} + +END_NAMESPACE_X3 diff --git a/x3py/source/core/x3manager/workpath.h b/x3py/source/core/x3manager/workpath.h new file mode 100644 index 0000000..d131b57 --- /dev/null +++ b/x3py/source/core/x3manager/workpath.h @@ -0,0 +1,33 @@ +// x3py framework: https://github.com/rhcad/x3py +#ifndef X3_CORE_WORKPATH_IMPL_H +#define X3_CORE_WORKPATH_IMPL_H + +#include +#include + +BEGIN_NAMESPACE_X3 + +class CWorkPath : public IAppWorkPath +{ + X3BEGIN_CLASS_DECLARE0(CWorkPath) + X3DEFINE_INTERFACE_ENTRY(IAppWorkPath) + X3END_CLASS_DECLARE() +protected: + CWorkPath() {} + +private: + virtual std::wstring getWorkPath(); + virtual void setWorkPath(const std::wstring&); + virtual std::wstring getLocalAppDataPath(const wchar_t*); + virtual std::wstring getTranslationsPath(const wchar_t*); + virtual std::wstring getConfigPath(const wchar_t*); + +private: + bool isVistaDisk(); + bool getLocalAppDataPath_(char*); + + std::wstring m_path; +}; + +END_NAMESPACE_X3 +#endif \ No newline at end of file diff --git a/x3py/source/public/mk/Makefile.libp b/x3py/source/public/mk/Makefile.libp new file mode 100644 index 0000000..619ce2f --- /dev/null +++ b/x3py/source/public/mk/Makefile.libp @@ -0,0 +1,30 @@ +# Included by Makefile of static library project. +# x3py framework: https://github.com/rhcad/x3py + +TARGET =$(PLUGINS_DIR)/$(PROJNAME)$(LIBEXT) +SOURCES =$(wildcard *.cpp) +OBJS =$(SOURCES:.cpp=$(OBJEXT)) + +all: $(TARGET) +$(TARGET): $(OBJS) + $(AR) $(ARFLAGS)$@ $(OBJS) + +%.d: %.cpp + $(DEPEND_CC) $@ $(INCLUDES) $< +%$(OBJEXT): %.cpp + $(CPP) $(CPPFLAGS) $(INCLUDES) -c $< + +ifndef clean +include $(SOURCES:.cpp=.d) +endif + +clean: +ifndef SWIG_TYPE + rm -rf *.d *.o *.obj +ifdef cleanall + rm -rf $(TARGET) +endif +ifdef touch + touch -c * +endif +endif diff --git a/x3py/source/public/mk/Makefile.pln b/x3py/source/public/mk/Makefile.pln new file mode 100644 index 0000000..cc21677 --- /dev/null +++ b/x3py/source/public/mk/Makefile.pln @@ -0,0 +1,41 @@ +# Included by Makefile of plugin project. +# x3py framework: https://github.com/rhcad/x3py + +ifdef APPTYPE +TARGET =$(INSTALL_DIR)/$(PROJNAME)$(APPEXT) +else +TARGET =$(PLUGINS_DIR)/$(PROJNAME).pln +endif +SOURCES =$(wildcard *.cpp) +OBJS =$(SOURCES:.cpp=$(OBJEXT)) + +ifdef VCBIN +RCFILES =$(wildcard *.rc) +RESFILES =$(RCFILES:.rc=.res) +endif + +all: $(TARGET) +$(TARGET): $(OBJS) $(RESFILES) + $(LINK) $(LDFLAGS) $(OUTFLAG)$@ $(OBJS) $(LIBS) $(RESFILES) + +%.d: %.cpp + $(DEPEND_CC) $@ $(INCLUDES) $< +%$(OBJEXT): %.cpp + $(CPP) $(CPPFLAGS) $(INCLUDES) -c $< +%.res: %.rc + "$(WINSDKBIN)rc" -Fo$@ $(INCLUDES) $(WINSDKINC) $< + +ifndef clean +include $(SOURCES:.cpp=.d) +endif + +clean: +ifndef SWIG_TYPE + rm -rf *.d *.o *.obj *_wrap.* ._* *.res +ifdef cleanall + rm -rf $(TARGET) +endif +ifdef touch + touch -c * +endif +endif diff --git a/x3py/source/public/mk/Makefile.qt4 b/x3py/source/public/mk/Makefile.qt4 new file mode 100644 index 0000000..70393ec --- /dev/null +++ b/x3py/source/public/mk/Makefile.qt4 @@ -0,0 +1,110 @@ +# Included by Makefile of QT project. +# x3py framework: https://github.com/rhcad/x3py + +ifdef APPTYPE +TARGET =$(INSTALL_DIR)/$(PROJNAME)$(APPEXT) +else +TARGET =$(PLUGINS_DIR)/$(PROJNAME).pln +endif +OBJDIR =._qt +SOURCES =$(wildcard *.cpp) +OBJS =$(addprefix $(OBJDIR)/, $(SOURCES:.cpp=$(OBJEXT))) + +ifndef QT4_INCLUDE +ifdef QTDIR +QT4_INCLUDE =$(QTDIR)/include +QT4_LIB =$(QTDIR)/lib +QT4_BIN =$(QTDIR)/bin/ +endif +endif + +ifdef QT4_INCLUDE + +INCLUDES += -I"$(QT4_INCLUDE)" \ + -I"$(QT4_INCLUDE)/QtCore" \ + -I"$(QT4_INCLUDE)/QtGui" \ + -I"$(QT4_INCLUDE)/QtWidgets" \ + -I"$(QT4_INCLUDE)/qtmain" \ + -I"$(OBJDIR)" \ + -DQT_CORE_LIB -DQT_GUI_LIB + +ifdef VCBIN +RCFILES =$(wildcard *.rc) +RESFILES =$(addprefix $(OBJDIR)/, $(RCFILES:.rc=.res)) +endif + +ifdef IS_WIN +QTLIB_EXT =4$(LIBEND) +else +QTLIB_EXT =$(LIBEND) +endif + +ifdef IS_MACOSX +LIBS += -F$(QT4_LIB) \ + -framework QtCore \ + -framework QtGui \ + -framework QtWidgets \ + -Wl,-rpath,$(QT4_LIB) +else +LIBS += $(LIBPATHFLAG)"$(QT4_LIB)" \ + $(LIBFLAG)QtCore$(QTLIB_EXT) \ + $(LIBFLAG)QtGui$(QTLIB_EXT) +endif +ifdef IS_WIN +LIBS += $(LIBFLAG)qtmain$(LIBEND) +endif + +UIFILES =$(wildcard *.ui) +UIHFILES =$(addprefix $(OBJDIR)/ui_, $(UIFILES:.ui=.h)) +QRCFILES =$(wildcard *.qrc) +QRCCPPS =$(addprefix $(OBJDIR)/qrc_, $(QRCFILES:.qrc=.cpp)) + +all: $(TARGET) +$(TARGET): $(OBJS) $(RESFILES) + $(LINK) $(LDFLAGS) $(OUTFLAG)$@ $(OBJS) $(LIBS) $(RESFILES) + +%.d: %.cpp + $(DEPEND_CC) $@ $(INCLUDES) $< + +$(OBJDIR)/%$(OBJEXT): %.cpp + -@test -d $(OBJDIR) || mkdir $(OBJDIR) + $(CPP) $(CPPFLAGS) $(INCLUDES) $(OFLAG)$@ -c $< + +$(MOCS:.h=.d): %.d: %.cpp $(OBJDIR)/moc_%.cpp $(UIHFILES) $(QRCCPPS) + $(DEPEND_CC) $@ $(INCLUDES) $< + +$(OBJDIR)/ui_%.h: %.ui + -@test -d $(OBJDIR) || mkdir $(OBJDIR) + "$(QT4_BIN)uic" -o $@ $< + +$(OBJDIR)/qrc_%.cpp: %.qrc + -@test -d $(OBJDIR) || mkdir $(OBJDIR) + "$(QT4_BIN)rcc" -name $(basename $<) -no-compress $< -o $@ + +$(OBJDIR)/moc_%.cpp: %.h + -@test -d $(OBJDIR) || mkdir $(OBJDIR) + "$(QT4_BIN)moc" $< -o $@ $(INCLUDES) + +$(OBJDIR)/%.res: %.rc + -@test -d $(OBJDIR) || mkdir $(OBJDIR) + "$(WINSDKBIN)rc" -Fo$@ $(INCLUDES) $(WINSDKINC) $< + +ifndef clean +include $(SOURCES:.cpp=.d) +endif + +else +all: + @echo QT4_INCLUDE not defined. +endif #QT4_INCLUDE + +clean: +ifndef SWIG_TYPE + rm -rf *.d *.o *.obj *_wrap.* ._* +ifdef cleanall + rm -rf $(TARGET) +endif +ifdef touch + touch -c * +endif +endif diff --git a/x3py/source/public/swig/Makefile.plswig b/x3py/source/public/swig/Makefile.plswig new file mode 100644 index 0000000..2fcdc69 --- /dev/null +++ b/x3py/source/public/swig/Makefile.plswig @@ -0,0 +1,25 @@ +# Included by Makefile of plugin project integrated with swig. +# x3py framework: https://github.com/rhcad/x3py + +ifndef SWIG_TYPE +include $(SRCPUB_DIR)/mk/Makefile.pln +else + +SOURCES =$(wildcard *.cpp) +OBJDIR =._$(SWIG_TYPE)o/ +OBJS =$(addprefix $(OBJDIR), $(SOURCES:.cpp=$(OBJEXT))) +CPPFLAGS += -DPLUGIN_SWIG + +include $(SRCPUB_DIR)/swig/Makefile.swig + +%.d: %.cpp + $(DEPEND_CC) $@ $(INCLUDES) $< +$(OBJDIR)%$(OBJEXT): %.cpp + -@test -d $(OBJDIR) || mkdir $(OBJDIR) + $(CPP) $(CPPFLAGS) $(INCLUDES) -c $< $(OFLAG)$@ + +ifndef clean +include $(SOURCES:.cpp=.d) +endif + +endif #SWIG_TYPE diff --git a/x3py/source/public/swig/Makefile.swig b/x3py/source/public/swig/Makefile.swig new file mode 100644 index 0000000..cb96f9a --- /dev/null +++ b/x3py/source/public/swig/Makefile.swig @@ -0,0 +1,191 @@ +# Included by Makefile of swig project. +# x3py framework: https://github.com/rhcad/x3py + +# SWIG_TYPE == ? +USE_PYTHON :=$(shell echo $(SWIG_TYPE)|grep -i python) +USE_PERL :=$(shell echo $(SWIG_TYPE)|grep -i perl) +USE_JAVA :=$(shell echo $(SWIG_TYPE)|grep -i java) +USE_CSHARP :=$(shell echo $(SWIG_TYPE)|grep -i csharp) +USE_RUBY :=$(shell echo $(SWIG_TYPE)|grep -i ruby) + +# The extension of the target file to compile. +ifdef IS_WIN +ifdef USE_PYTHON +SWIG_EXT =.pyd +else +SWIG_EXT =.dll +endif +else +SWIG_EXT =.so +endif + +# The prefix of the target file to compile. +ifdef USE_PYTHON +SWIG_PRE =_ +else +ifdef USE_CSHARP +SWIG_PRE =_ +endif +endif + +ifdef USE_PYTHON +SWIG_INCLUDE ?=$(PYTHON_INCLUDE) +SWIG_LIBPATH :=$(PYTHON_LIB) +SWIG_LIBFILE :=$(PYTHON_LIBFILE) +SWIG_TESTEXT =.py +WRAPTARGET =$(PROJNAME).py +CPPFLAGS += -DUSE_PYTHON +endif + +ifdef USE_PERL +SWIG_INCLUDE ?=$(PERL5_INCLUDE) +SWIG_LIBPATH :=$(PERL5_LIB) +SWIG_LIBFILE :=$(PERL5_LIBFILE) +SWIG_TESTEXT =.pl +WRAPTARGET =$(PROJNAME).pm +CPPFLAGS += -DUSE_PERL +endif + +ifdef USE_JAVA +SWIG_INCLUDE ?=$(JAVA_INCLUDE) +SWIG_TESTEXT =.java +WRAPTARGET =$(PROJNAME).jar +CPPFLAGS += -DUSE_JAVA +endif + +ifdef USE_CSHARP +SWIG_TESTEXT =.cs +WRAPTARGET =$(PROJNAME)$(SWIG_EXT) +CPPFLAGS += -DUSE_CSHARP +endif + +ifdef USE_RUBY +SWIG_INCLUDE ?=$(RUBY_INCLUDE) +SWIG_LIBPATH :=$(RUBY_LIB) +SWIG_LIBFILE :=$(RUBY_LIBFILE) +SWIG_TESTEXT =.rb +WRAPTARGET =$(PROJNAME).rb +CPPFLAGS += -DUSE_RUBY +endif + +ifdef SWIG_INCLUDE +INCLUDES += -I"$(SWIG_INCLUDE)" +endif +ifdef SWIG_LIBPATH +LIBS += $(LIBPATHFLAG)"$(SWIG_LIBPATH)" +endif +ifdef SWIG_LIBFILE +LIBS += $(LIBFLAG)$(SWIG_LIBFILE)$(LIBEND) +endif + +ifdef USE_JAVA +SWIGTMP =._$(SWIG_TYPE) +else +ifdef USE_CSHARP +SWIGTMP =._$(SWIG_TYPE) +endif +endif + +SWIG_TESTDIR ?=$(INSTALL_DIR)/$(SWIG_TYPE) +ifdef USE_PYTHON +SWIG_OUTDIR ?=$(SWIG_TESTDIR)/$(PKGNAME) +else +SWIG_OUTDIR ?=$(SWIG_TESTDIR) +endif + +SWIG_CC ="$(SWIG_BIN)swig" -c++ -$(SWIG_TYPE) +ifdef USE_CSHARP +SWIG_CC += -namespace $(PKGNAME).$(PROJNAME) -dllimport _$(PROJNAME) +endif +ifdef SWIGTMP +SWIG_CC += -outdir $(SWIGTMP) +else +SWIG_CC += -outdir $(SWIG_OUTDIR) +endif + +#------------------------------------------------ +TARGET =$(SWIG_PRE)$(PROJNAME)$(SWIG_EXT) +WRAPFILE =$(PROJNAME)_$(SWIG_TYPE)_wrap +OBJS +=$(WRAPFILE)$(OBJEXT) +TESTFILE :=test$(PROJNAME)$(SWIG_TESTEXT) +REMOTE_TARGET =$(SWIG_OUTDIR)/$(TARGET) +REMOTE_WRAPTARGET =$(SWIG_OUTDIR)/$(WRAPTARGET) +REMOTE_TESTFILE :=$(SWIG_TESTDIR)/$(TESTFILE) +HASTESTFILE =(test -e $(TESTFILE)) + +.PHONY: swig clean $(TESTFILE) + +all: +swig: $(REMOTE_TARGET) $(REMOTE_WRAPTARGET) $(REMOTE_TESTFILE) + +$(REMOTE_TARGET): $(OBJS) + -@test -d $(SWIG_TESTDIR) || mkdir $(SWIG_TESTDIR) + -@test -d $(SWIG_OUTDIR) || mkdir $(SWIG_OUTDIR) + $(LINK) $(LDFLAGS) $(OUTFLAG)$@ $(OBJS) $(LIBS) + +%$(OBJEXT): %.cxx + $(CPP) $(subst -Wall ,,$(subst -W4 ,,$(CPPFLAGS))) $(INCLUDES) -c $< + +#------------------------------------------------ + +$(WRAPFILE).cxx: $(PROJNAME).i + @echo --Making $(SWIG_TYPE) project $(PROJNAME)... + -@test -d $(SWIG_TESTDIR) || mkdir $(SWIG_TESTDIR) + -@test -d $(SWIG_OUTDIR) || mkdir $(SWIG_OUTDIR) +ifdef SWIGTMP + -@test -d $(SWIGTMP) || mkdir $(SWIGTMP); rm -rf $(SWIGTMP)/*.* +endif + $(SWIG_CC) -o $(WRAPFILE).cxx $(INCLUDES) $< +ifdef USE_PYTHON + @test -e $(SWIG_OUTDIR)/__init__.py || echo "#empty" > $(SWIG_OUTDIR)/__init__.py +endif + +#------------------------------------------------ + +$(REMOTE_WRAPTARGET): $(WRAPFILE).cxx +ifdef SWIGTMP + @test -d $(SWIGTMP) || (rm -rf $(WRAPFILE).cxx; $(MAKE) $(WRAPFILE).cxx) +endif +ifdef USE_JAVA + @cd $(SWIGTMP); "$(JAVA_BIN)javac" *.java; \ + "$(JAVA_BIN)jar" cfM $(WRAPTARGET) *.class; \ + cp -v $(WRAPTARGET) ../$(SWIG_OUTDIR) +endif +ifdef USE_CSHARP + @cd $(SWIGTMP); "$(CSC_BIN)csc" -nologo -t:library -out:$(WRAPTARGET) *.cs; \ + cp -v $(WRAPTARGET) ../$(SWIG_OUTDIR) +endif + +#------------------------------------------------ + +$(TESTFILE): +ifdef SWIG_TESTEXT + -@!$(HASTESTFILE) || cp -v $(TESTFILE) $(SWIG_TESTDIR) +endif + +$(REMOTE_TESTFILE): $(REMOTE_WRAPTARGET) $(TESTFILE) +ifdef SWIG_TESTEXT +ifdef USE_JAVA + @!$(HASTESTFILE) || (cd $(SWIG_TESTDIR); \ + "$(JAVA_BIN)javac" -cp $(WRAPTARGET) $(TESTFILE)) +endif +ifdef USE_CSHARP + @!$(HASTESTFILE) || (cd $(SWIG_TESTDIR); \ + "$(CSC_BIN)csc" -nologo -t:exe -r:$(WRAPTARGET) $(TESTFILE)) +endif +endif #SWIG_TESTEXT + +#------------------------------------------------ + +clean: +ifndef SWIG_TYPE + rm -rf *.d *$(OBJEXT) *_wrap.* ._* +ifdef touch + touch -c * +endif +else + rm -rf *.d $(WRAPFILE)* ._$(SWIG_TYPE)* +ifdef cleanall + rm -rf $(REMOTE_TARGET) $(REMOTE_WRAPTARGET) $(REMOTE_TESTFILE) +endif +endif diff --git a/x3py/source/public/swig/observer.i b/x3py/source/public/swig/observer.i new file mode 100644 index 0000000..4562110 --- /dev/null +++ b/x3py/source/public/swig/observer.i @@ -0,0 +1,20 @@ +/* observer.i: included by swig projects which use eventobserver.h .*/ +#ifndef X3_OBSERVER_PLUGIN_SWIGI +#define X3_OBSERVER_PLUGIN_SWIGI + +%{ +#ifndef PLUGIN_NAME +#define PLUGIN_NAME "x3manager" +#endif +%} +%include + +%{ +#ifndef PLUGIN_SWIG +#include +#endif +%} + +%include + +#endif diff --git a/x3py/source/public/swig/plugin.i b/x3py/source/public/swig/plugin.i new file mode 100644 index 0000000..a952794 --- /dev/null +++ b/x3py/source/public/swig/plugin.i @@ -0,0 +1,28 @@ +/* plugin.i: included by swig projects. + Define PLUGIN_NAME before include this file to auto load internal plugin. +*/ +#ifndef X3_PLUGIN_SWIGI +#define X3_PLUGIN_SWIGI + +%{ +#include + +#ifdef PLUGIN_SWIG // pluginimpl.h has been included +#undef PLUGIN_NAME +#define PLUGIN_NAME "x3manager" +#define X3_EXCLUDE_CREATEOBJECT +#endif +#include // load PLUGIN_NAME.pln when not use useplugins.h + +#define X3THROW_NULLPOINTERERROR(name) \ + printf("NullPointerError occurs, interface name: %s\n", name); \ + throw x3::NullPointerError() +#include +%} + +%include +%include + +%template(AnyObject) x3::Object; + +#endif diff --git a/x3py/x3py.pro b/x3py/x3py.pro new file mode 100644 index 0000000..e1b449e --- /dev/null +++ b/x3py/x3py.pro @@ -0,0 +1,138 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-01-04T12:31:26 +# +#------------------------------------------------- + +QT -= gui + +CONFIG += c++11 + +TARGET = x3manager +TEMPLATE = lib +TARGET_EXT = .pln + +DEFINES += X3PY_LIBRARY + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + source/core/x3manager/module.cpp \ + source/core/x3manager/plugins.cpp \ + source/core/x3manager/workpath.cpp + +HEADERS +=\ + interface/core/manager/iplugins.h \ + interface/core/manager/iworkpath.h \ + interface/core/manager/x3manager.h \ + interface/core/module/classentry.h \ + interface/core/module/classmacro.h \ + interface/core/module/moduleitem.h \ + interface/core/module/modulemacro.h \ + interface/core/module/normalobject.h \ + interface/core/module/pluginimpl.h \ + interface/core/module/plugininc.h \ + interface/core/module/singletonobj.h \ + interface/core/nonplugin/scanplugins.h \ + interface/core/nonplugin/swigext.h \ + interface/core/nonplugin/useplugin.h \ + interface/core/nonplugin/useplugins.h \ + interface/core/observer/eventobserver.h \ + interface/core/observer/fireevent.h \ + interface/core/observer/fireobjevent.h \ + interface/core/observer/observerimpl.h \ + interface/core/observer/observerobject.h \ + interface/core/portability/func_s.h \ + interface/core/portability/pathstr.h \ + interface/core/portability/portimpl.h \ + interface/core/portability/uniximpl.h \ + interface/core/portability/winimpl.h \ + interface/core/portability/x3port.h \ + interface/core/portability/x3unix.h \ + interface/core/portability/x3win.h \ + interface/core/utilfunc/convstr.h \ + interface/core/utilfunc/loadmodule.h \ + interface/core/utilfunc/lockcount.h \ + interface/core/utilfunc/lockrw.h \ + interface/core/utilfunc/readints.h \ + interface/core/utilfunc/roundstr.h \ + interface/core/utilfunc/safecall.h \ + interface/core/utilfunc/scanfiles.h \ + interface/core/utilfunc/syserrstr.h \ + interface/core/utilfunc/vecfunc.h \ + interface/core/iobject.h \ + interface/core/objptr.h \ + source/core/x3manager/plugins.h \ + source/core/x3manager/workpath.h \ + interface/core/observer/fireeventex.h \ + interface/core/observer/fireobjeventex.h + +{ + CONFIG(debug, debug|release){ + DESTDIR = $$PWD/../bin/debug/CbersPlugins + } + else{ + DESTDIR = $$PWD/../bin/release/CbersPlugins + } +} + +INCLUDEPATH += $$PWD/interface/core +DEPENDPATH += $$PWD/interface/core + +# Copies the given files to the destination directory +defineReplace(copyToDir) { + files = $$1 + DIR = $$2 + SRCDIR = $$3 + LINK = + + win32:DIR ~= s,/,\\,g + win32{ + LINK += if not exist $$quote($$DIR) ( $$QMAKE_MKDIR $$quote($$DIR) ) $$escape_expand(\\n\\t) + } + unix{ + LINK += $$QMAKE_MKDIR $$quote($$DIR) $$escape_expand(\\n\\t) + } + for(FILE, files) { + !isEmpty(SRCDIR){ + FILE = $$SRCDIR/$$FILE + } + win32:FILE ~= s,/,\\,g + LINK += $$QMAKE_COPY $$quote($$FILE) $$quote($$DIR) $$escape_expand(\\n\\t) + } + return($$LINK) +} + +SDK_PATH = $$PWD/../include/x3py/ +win32{ + SDK_PATH ~= s,/,\\,g + QMAKE_POST_LINK += if exist $$quote($$SDK_PATH) ( rmdir /S /Q $$quote($$SDK_PATH) ) $$escape_expand(\\n\\t) + QMAKE_POST_LINK += cd $$quote($$PWD) $$escape_expand(\\n\\t) +} +unix{ + QMAKE_POST_LINK += rm -rf $$quote($$SDK_PATH) $$escape_expand(\\n\\t) + QMAKE_POST_LINK += cd $$quote($$PWD) $$escape_expand(\\n\\t) +} + +QMAKE_POST_LINK += $$copyToDir("interface/core/*.h", $$SDK_PATH, $$PWD) +QMAKE_POST_LINK += $$copyToDir("interface/core/manager/*.h", $$SDK_PATH/manager/, $$PWD) +QMAKE_POST_LINK += $$copyToDir("interface/core/module/*.h", $$SDK_PATH/module/, $$PWD) +QMAKE_POST_LINK += $$copyToDir("interface/core/nonplugin/*.h", $$SDK_PATH/nonplugin/, $$PWD) +QMAKE_POST_LINK += $$copyToDir("interface/core/observer/*.h", $$SDK_PATH/observer/, $$PWD) +QMAKE_POST_LINK += $$copyToDir("interface/core/portability/*.h", $$SDK_PATH/portability/, $$PWD) +QMAKE_POST_LINK += $$copyToDir("interface/core/utilfunc/*.h", $$SDK_PATH/utilfunc/, $$PWD) + +unix{ + SRCEXT = .so + DSTEXT = .pln + QMAKE_POST_LINK += mv -f $$quote($$DESTDIR/lib$$TARGET$$SRCEXT) $$quote($$DESTDIR/$$TARGET$$DSTEXT) $$escape_expand(\\n\\t) +} diff --git "a/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/lib.png" "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/lib.png" new file mode 100644 index 0000000..0566f1d Binary files /dev/null and "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/lib.png" differ diff --git "a/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/lib@2x.png" "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/lib@2x.png" new file mode 100644 index 0000000..90a842d Binary files /dev/null and "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/lib@2x.png" differ diff --git "a/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/module.cpp" "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/module.cpp" new file mode 100644 index 0000000..5a1e41d --- /dev/null +++ "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/module.cpp" @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include "module/plugininc.h" +#include "module/pluginimpl.h" +#include "module/modulemacro.h" +#include "observer/observerimpl.h" +//#include "%{ProjectName}.h" + +XBEGIN_DEFINE_MODULE() + //XDEFINE_CLASSMAP_ENTRY(%{ProjectName}) +XEND_DEFINE_MODULE_DLL() + +QTranslator gTranslator; +OUTAPI bool x3InitializePlugin() +{ + ////////////////////////////////////////////////////////////// + // Load Translator + QSettings mySettings; + QString i18nPath = QApplication::applicationDirPath() + QDir::separator() + "i18n"; + QString myUserLocale = mySettings.value( "locale/userLocale", "" ).toString(); + bool myLocaleOverrideFlag = mySettings.value( "locale/overrideFlag", false ).toBool(); + QString myTranslationCode; + if ( !myTranslationCode.isNull() && !myTranslationCode.isEmpty() ) + { + mySettings.setValue( "locale/userLocale", myTranslationCode ); + } + else + { + if ( !myLocaleOverrideFlag || myUserLocale.isEmpty() ) + { + myTranslationCode = QLocale::system().name(); + mySettings.setValue( "locale/userLocale", myTranslationCode ); + } + else + { + myTranslationCode = myUserLocale; + } + } + + if ( myTranslationCode != "C" ) + { + if ( gTranslator.load( QString( "%{ProjectName}_" ) + myTranslationCode, i18nPath ) ) + { + QApplication::installTranslator( &gTranslator ); + } + else + { + qWarning( "loading of %{ProjectName} translation failed [%s]", QString( "%1/%{ProjectName}_%2" ).arg( i18nPath ).arg( myTranslationCode ).toLocal8Bit().constData() ); + } + } + ////////////////////////////////////////////////////////////// + return true; +} + +OUTAPI void x3UninitializePlugin() +{ + if( !gTranslator.isEmpty() ) + { + QApplication::removeTranslator( &gTranslator ); + } +} diff --git "a/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/project.pro" "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/project.pro" new file mode 100644 index 0000000..9f0208d --- /dev/null +++ "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/project.pro" @@ -0,0 +1,28 @@ +TEMPLATE = lib +TARGET = %{ProjectName} +QT += core + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +# Input +SOURCES += \ + module.cpp + +HEADERS += \ + +PROJECT_PATH = $$PWD +SDK_PATH = $$PROJECT_PATH/../../ +#TRANSLATION_LANGS = zh_CN +include( ../../include/pluginconfig.pri ) +QMAKE_POST_LINK += $$copyToDir($$PROJECT_PATH/*.png, $$DESTDIR/../Skins/) \ No newline at end of file diff --git "a/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/wizard.json" "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/wizard.json" new file mode 100644 index 0000000..2813965 --- /dev/null +++ "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/CbersPlugin/wizard.json" @@ -0,0 +1,45 @@ +{ + "version": 1, + "supportedProjectTypes": [ "Qbs.QbsProject", "Qt4ProjectManager.Qt4Project" ], + "id": "CbersPluginProject", + "category": "G.Library", + "trDescription": "Creates a custom SPD plugin.", + "trDisplayName": "CbersPlugin Project", + "trDisplayCategory": "Library", + "icon": "lib.png", + "featuresRequired": [ "QtSupport.Wizards.FeatureDesktop" ], + + "pages": + [ + { + "trDisplayName": "Project Location", + "trShortTitle": "Location", + "typeId": "Project", + "data": { "trDescription": "This wizard creates an empty CbersPlugin Project .pro file." } + }, + { + "trDisplayName": "Project Management", + "trShortTitle": "Summary", + "typeId": "Summary" + } + ], + "generators": + [ + { + "typeId": "File", + "data": + [ + { + "source": "project.pro", + "target": "%{ProjectName}.pro", + "openAsProject": true + }, + { + "source": "module.cpp", + "target": "module.cpp", + "openInEditor": true + } + ] + } + ] +} diff --git "a/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/classes/CbersPluginClass/file.cpp" "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/classes/CbersPluginClass/file.cpp" new file mode 100644 index 0000000..a117968 --- /dev/null +++ "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/classes/CbersPluginClass/file.cpp" @@ -0,0 +1,241 @@ +%{Cpp:LicenseTemplate}\ +#include "%{HdrFileName}" +#include +@if '%{IncludeIUICommand}' || '%{IncludeIUITool}' +#include +#include +#include +@endif + +@if '%{Base}' === 'QObject' +%{CN}::%{CN}(QObject *parent) : QObject(parent) +@elsif '%{Base}' === 'QWidget' || '%{Base}' === 'QMainWindow' || '%{Base}' === 'QDockWidget' || '%{Base}' === 'QTableWidget' +%{CN}::%{CN}(QWidget *parent) : %{Base}(parent) +@else +%{CN}::%{CN}() +@endif +{ +@if '%{IncludeIUIView}' || '%{IncludeIUICommand}' || '%{IncludeIUITool}' + Name(QStringLiteral("%{PluginName}")); + Caption(QStringLiteral("%{PluginCaption}")); + Category(QStringLiteral("%{PluginCategory}")); + Tooltip(QStringLiteral("%{PluginTooltip}")); + Description(QStringLiteral("%{PluginDescription}")); + BitmapName(QStringLiteral("%{PluginBitmapName}")); + +@if '%{Base}' === 'QWidget' || '%{Base}' === 'QMainWindow' || '%{Base}' === 'QDockWidget' || '%{Base}' === 'QTableWidget' + setWindowTitle(Name()); +@endif + +@if '%{IncludeIUIView}' === '' && ('%{IncludeIUICommand}' || '%{IncludeIUITool}') + mToolButton = Q_NULLPTR; + mDefaultIcon = true; + +@if '%{Base}' === 'QWidget' || '%{Base}' === 'QMainWindow' || '%{Base}' === 'QTableWidget' + hide(); +@endif +@endif +@endif +} + +%{CN}::~%{CN}() +{ +@if '%{IncludeIUIView}' || '%{IncludeIUICommand}' || '%{IncludeIUITool}' + UnInitialize(); +@endif +} + +@if '%{IncludeIUIView}' || '%{IncludeIUICommand}' || '%{IncludeIUITool}' + // IUIPlugin + bool %{CN}::Initialize() + { +@if '%{IncludeIUIView}' === '' && ('%{IncludeIUICommand}' || '%{IncludeIUITool}') + mToolButton = new QToolButton(); + mToolButton->setText(Name()); + mToolButton->setToolTip(Tooltip()); + mToolButton->setIconSize(QSize(32, 32)); + mToolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + mToolButton->setAutoRaise(true); + mToolButton->setMouseTracking(true); + QString strBitmapName = BitmapName(); + QIcon icon; + if( !strBitmapName.isEmpty() ) + { + strBitmapName = QString("%1/Skins/%2.png").arg(QApplication::applicationDirPath()).arg(strBitmapName); + QFileInfo fileInfo(strBitmapName); + if( !fileInfo.exists() ) + { + strBitmapName = QString("%1/Skins/default.png").arg(QApplication::applicationDirPath()); + fileInfo.setFile(strBitmapName); + } + else + mDefaultIcon = false; + + if( fileInfo.exists() ) + icon.addFile(strBitmapName); + } + + if( !icon.isNull() ) + { + mToolButton->setIcon(icon); +@if '%{Base}' === 'QWidget' || '%{Base}' === 'QMainWindow' || '%{Base}' === 'QDockWidget' || '%{Base}' === 'QTableWidget' + setWindowIcon(icon); +@endif + } + +@if '%{IncludeIUITool}' + mToolButton->setCheckable(true); + mToolButton->setEnabled(false); + this->connect(mToolButton, SIGNAL(clicked(bool)), this, SLOT(clicked(bool))); +@else +@if '%{Base}' === 'QDockWidget' + mToolButton->setCheckable(true); + QAction* actionDockWidget = toggleViewAction(); + actionDockWidget->setIcon(icon); + actionDockWidget->setText(Name()); + actionDockWidget->setToolTip(Tooltip()); + mToolButton->setDefaultAction(actionDockWidget); + this->connect(mToolButton, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); +@else + mToolButton->setCheckable(false); + this->connect(mToolButton, SIGNAL(clicked()), this, SLOT(clicked())); +@endif +@endif +@endif + +@if '%{IncludeIUIEvent}' + // Only Support appoint Events + //supportsEvent("EventKey"); + registerHandlers(); +@endif + return true; + } + + bool %{CN}::UnInitialize() + { +@if '%{IncludeIUIView}' === '' && ('%{IncludeIUICommand}' || '%{IncludeIUITool}') + if( mToolButton!=Q_NULLPTR ) + delete mToolButton; + mToolButton = Q_NULLPTR; +@endif + +@if '%{IncludeIUIEvent}' + unregisterHandlers(); +@endif +@if '%{Base}' === 'QWidget' || '%{Base}' === 'QMainWindow' || '%{Base}' === 'QDockWidget' || '%{Base}' === 'QTableWidget' + hide(); +@endif + return true; + } + + bool %{CN}::SetBuddy(x3::IObject* val) + { + if( m_spBuddy==val ) + return true; + + m_spBuddy = val; + if( !m_spBuddy.valid() ) + { +@if '%{IncludeIUIView}' === '' && ('%{IncludeIUICommand}' || '%{IncludeIUITool}') + mToolButton->setEnabled(false); +@endif + return false; + } + +@if '%{IncludeIUIView}' === '' && ('%{IncludeIUICommand}' || '%{IncludeIUITool}') + mToolButton->setEnabled(true); +@endif + + return true; + } + + bool %{CN}::readConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ) + { + if( !((IUIPlugin*)this)->readConfig(node, document, errorMessage) ) + return false; + + return true; + } + + bool %{CN}::writeConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ) + { + if( !((IUIPlugin*)this)->writeConfig(node, document, errorMessage) ) + return false; + + return true; + } +@if '%{IncludeIUIView}' + + // IUIView + QWidget* %{CN}::getViewWidget() + { +@if '%{Base}' === 'QWidget' || '%{Base}' === 'QMainWindow' || '%{Base}' === 'QDockWidget' || '%{Base}' === 'QTableWidget' + return this; +@else + return Q_NULLPTR; +@endif + } +@else +@if '%{IncludeIUICommand}' || '%{IncludeIUITool}' + + // IUICommand + QWidget* %{CN}::getButtonWidget() + { + return mToolButton; + } + + QWidget* %{CN}::getWndWidget() + { +@if '%{Base}' === 'QWidget' || '%{Base}' === 'QMainWindow' || '%{Base}' === 'QDockWidget' || '%{Base}' === 'QTableWidget' + show(); + return this; +@else + return Q_NULLPTR; +@endif + } +@endif +@endif +@endif +@if '%{IncludeIUIEvent}' + + // IAnythingEventObserver + bool %{CN}::OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam) + { +@if '%{IncludeIUIView}' === '' && '%{IncludeIUITool}' + if( _stricmp(eventKey.c_str(), "toolActived")==0 ) + { + if( sender==(IUIPlugin*)this ) + return true; + } +@else + //if( _stricmp(eventKey.c_str(), "EventKey")==0 ) + //{ + //} +@endif + return true; + } +@endif + +@if '%{IncludeIUIView}' === '' && ('%{IncludeIUICommand}' || '%{IncludeIUITool}') +@if '%{IncludeIUITool}' + void %{CN}::clicked(bool checked) + { + } +@else +@if '%{Base}' === 'QDockWidget' + void %{CN}::toggled(bool checked) + { + if( checked ) + { + setVisible(true); + raise(); + } + } +@else + void %{CN}::clicked() + { + } +@endif +@endif +@endif +%{JS: Cpp.closeNamespaces('%{Class}')}\ diff --git "a/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/classes/CbersPluginClass/file.h" "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/classes/CbersPluginClass/file.h" new file mode 100644 index 0000000..cd1debf --- /dev/null +++ "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/classes/CbersPluginClass/file.h" @@ -0,0 +1,139 @@ +%{Cpp:LicenseTemplate}\ +#ifndef %{GUARD} +#define %{GUARD} +@if '%{Base}' +#include <%{Base}> +@endif +@if '%{IncludeIUIView}' === '' && ('%{IncludeIUICommand}' || '%{IncludeIUITool}') +#include +@endif + +@if '%{IncludeIUIEvent}' +#include "UIPluginsEvents.h" +@endif +@if '%{IncludeIUIView}' || '%{IncludeIUICommand}' || '%{IncludeIUITool}' +#include "UIPlugins.h" +USING_NAMESPACE_CBERSPLUGINS +@else +@if '%{IncludeIUIEvent}' +USING_NAMESPACE_CBERSPLUGINS +@endif +@endif +%{JS: Cpp.openNamespaces('%{Class}')} +@if '%{IncludeIUIView}' || '%{IncludeIUICommand}' || '%{IncludeIUITool}' +const char* const clsid%{CN} = "clsid%{CN}"; +@endif +@if '%{Base}' +class %{CN} : public %{Base} +@if '%{IncludeIUIView}' || '%{IncludeIUICommand}' || '%{IncludeIUITool}' + , public IUIPlugin +@if '%{IncludeIUIView}' + , public IUIView +@else +@if '%{IncludeIUICommand}' || '%{IncludeIUITool}' + , public IUICommand +@endif +@endif +@endif +@if '%{IncludeIUIEvent}' + , public IAnythingEventObserver +@endif +@else +class %{CN} +@if '%{IncludeIUIView}' || '%{IncludeIUICommand}' || '%{IncludeIUITool}' + : public IUIPlugin +@if '%{IncludeIUIView}' + , public IUIView +@else +@if '%{IncludeIUICommand}' || '%{IncludeIUITool}' + , public IUICommand +@endif +@endif +@if '%{IncludeIUIEvent}' + , public IAnythingEventObserver +@endif +@else +@if '%{IncludeIUIEvent}' + : public IAnythingEventObserver +@endif +@endif +@endif +{ +@if %{isQObject} + Q_OBJECT +@endif +@if '%{IncludeIUIView}' || '%{IncludeIUICommand}' || '%{IncludeIUITool}' + X3BEGIN_CLASS_DECLARE(%{CN}, clsid%{CN}) + X3DEFINE_INTERFACE_ENTRY(IUIPlugin) +@if '%{IncludeIUIView}' + X3DEFINE_INTERFACE_ENTRY(IUIView) +@else +@if '%{IncludeIUICommand}' || '%{IncludeIUITool}' + X3DEFINE_INTERFACE_ENTRY(IUICommand) +@endif +@endif + X3END_CLASS_DECLARE() +@endif + +public: +@if '%{Base}' === 'QObject' + explicit %{CN}(QObject *parent = 0); +@elsif '%{Base}' === 'QWidget' || '%{Base}' === 'QMainWindow' || '%{Base}' === 'QDockWidget' || '%{Base}' === 'QTableWidget' + explicit %{CN}(QWidget *parent = 0); +@else + %{CN}(); +@endif + ~%{CN}(); + +public: +@if '%{IncludeIUIView}' || '%{IncludeIUICommand}' || '%{IncludeIUITool}' + // IUIPlugin + virtual bool Initialize(); + virtual bool UnInitialize(); + virtual bool SetBuddy(x3::IObject* val); + virtual bool readConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ); + virtual bool writeConfig( const QDomNode& node, QDomDocument & document, QString& errorMessage ); +@if '%{IncludeIUIView}' + + // IUIView + virtual QWidget* getViewWidget(); +@else +@if '%{IncludeIUICommand}' || '%{IncludeIUITool}' + + // IUICommand + virtual QWidget* getButtonWidget(); + virtual QWidget* getWndWidget(); +@endif +@endif +@endif +@if '%{IncludeIUIEvent}' + + // IAnythingEventObserver + virtual bool OnAnything(x3::IObject* sender, const std::string& eventKey, const QVariant& wParam, const QVariant& lParam); +@endif + +@if %{isQObject} +signals: + +public slots: +@if '%{IncludeIUIView}' === '' && ('%{IncludeIUICommand}' || '%{IncludeIUITool}') +@if '%{IncludeIUITool}' + void clicked(bool checked = false); +@else +@if '%{Base}' === 'QDockWidget' + void toggled(bool checked); +@else + void clicked(); +@endif +@endif +@endif +@endif + +@if '%{IncludeIUIView}' === '' && ('%{IncludeIUICommand}' || '%{IncludeIUITool}') +protected: + QToolButton* mToolButton; + bool mDefaultIcon; +@endif +}; +%{JS: Cpp.closeNamespaces('%{Class}')} +#endif // %{GUARD}\ diff --git "a/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/classes/CbersPluginClass/file.png" "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/classes/CbersPluginClass/file.png" new file mode 100644 index 0000000..0566f1d Binary files /dev/null and "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/classes/CbersPluginClass/file.png" differ diff --git "a/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/classes/CbersPluginClass/wizard.json" "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/classes/CbersPluginClass/wizard.json" new file mode 100644 index 0000000..06f0d07 --- /dev/null +++ "b/\346\217\222\344\273\266\346\250\241\346\235\277/qtcreator/share/qtcreator/templates/wizards/classes/CbersPluginClass/wizard.json" @@ -0,0 +1,226 @@ +{ + "version": 1, + "supportedProjectTypes": [ ], + "id": "CbersPluginClass", + "category": "O.C++", + "trDescription": "Creates a CbersPlugin Class header and a source file for a new class that you can add to a CbersPlugin project.", + "trDisplayName": "CbersPlugin Class", + "trDisplayCategory": "C++", + "enabled": "%{JS: [ %{Plugins} ].indexOf('CppEditor') >= 0}", + + "options": + [ + { "key": "TargetPath", "value": "%{Path}" }, + { "key": "HdrPath", "value": "%{Path}/%{HdrFileName}" }, + { "key": "SrcPath", "value": "%{Path}/%{SrcFileName}" }, + { "key": "CN", "value": "%{JS: Cpp.className('%{Class}')}" }, + { "key": "Base", "value": "%{JS: ( '%{BaseCB}' === '' ) ? '%{BaseEdit}' : '%{BaseCB}'}" }, + { "key": "isQObject", "value": "%{JS: [ 'QObject', 'QWidget', 'QDockWidget', 'QMainWindow', 'QTableWidget' ].indexOf('%{Base}') >= 0 }" }, + { "key": "GUARD", "value": "%{JS: Cpp.headerGuard('%{HdrFileName}')}" } + ], + + "pages": + [ + { + "trDisplayName": "Define Class", + "trShortTitle": "Details", + "typeId": "Fields", + "data" : + [ + { + "name": "Class", + "trDisplayName": "Class name:", + "mandatory": true, + "type": "LineEdit", + "data": { "validator": "(?:(?:[a-zA-Z_][a-zA-Z_0-9]*::)*[a-zA-Z_][a-zA-Z_0-9]*|)" } + }, + { + "name": "BaseCB", + "trDisplayName": "Base class:", + "type": "ComboBox", + "data": + { + "items": [ { "trKey": "", "value": "" }, + "QObject", "QWidget", "QDockWidget", "QMainWindow", "QTableWidget" ], + "index": 1 + + } + }, + { + "name": "BaseEdit", + "type": "LineEdit", + "enabled": "%{JS: '%{BaseCB}' === ''}", + "mandatory": false, + "data": + { + "trText": "%{BaseCB}", + "trDisabledText": "%{BaseCB}" + } + }, + { + "name": "Sp2", + "type": "Spacer", + "data": { "size": 12 } + }, + { + "name": "PluginName", + "trDisplayName": "插件名称:", + "mandatory": true, + "type": "LineEdit", + "data": { "trText": "%{JS: '%{Class}'}" } + }, + { + "name": "PluginCaption", + "trDisplayName": "标题:", + "mandatory": true, + "type": "LineEdit", + "data": { "trText": "%{JS: '%{PluginName}'}" } + }, + { + "name": "PluginCategory", + "trDisplayName": "分类:", + "mandatory": true, + "type": "LineEdit", + "data": { "trText": "Plugins" } + }, + { + "name": "PluginTooltip", + "trDisplayName": "提示:", + "mandatory": true, + "type": "LineEdit", + "data": { "trText": "%{JS: '%{PluginName}'}" } + }, + { + "name": "PluginDescription", + "trDisplayName": "描述:", + "mandatory": true, + "type": "LineEdit", + "data": { "trText": "%{JS: '%{PluginName}'}" } + }, + { + "name": "PluginBitmapName", + "trDisplayName": "图标:", + "mandatory": true, + "type": "LineEdit", + "data": { "trText": "%{JS: '%{Class}'}" } + }, + { + "name": "IncludeIUIView", + "trDisplayName": "视图插件", + "type": "CheckBox", + "data": + { + "checkedValue": "IUIView", + "uncheckedValue": "", + "checked": false + } + }, + { + "name": "IncludeIUICommand", + "trDisplayName": "命令按钮", + "type": "CheckBox", + "enabled": "%{JS: '%{IncludeIUIView}' === ''}", + "data": + { + "checkedValue": "IUICommand", + "uncheckedValue": "", + "checked": true + } + }, + { + "name": "IncludeIUITool", + "trDisplayName": "工具按钮", + "type": "CheckBox", + "enabled": "%{JS: '%{IncludeIUIView}' === ''}", + "data": + { + "checkedValue": "IUITool", + "uncheckedValue": "", + "checked": false + } + }, + { + "name": "IncludeIUIEvent", + "trDisplayName": "是否监听插件消息", + "type": "CheckBox", + "data": + { + "checkedValue": "IUIEvent", + "uncheckedValue": "", + "checked": true + } + }, + { + "name": "Sp2", + "type": "Spacer", + "data": { "size": 12 } + }, + { + "name": "HdrFileName", + "type": "LineEdit", + "trDisplayName": "Header file:", + "mandatory": true, + "data": { "trText": "%{JS: Cpp.classToFileName('%{Class}', '%{JS: Util.preferredSuffix('text/x-c++hdr')}')}" } + }, + { + "name": "SrcFileName", + "type": "LineEdit", + "trDisplayName": "Source file:", + "mandatory": true, + "data": { "trText": "%{JS: Cpp.classToFileName('%{Class}', '%{JS: Util.preferredSuffix('text/x-c++src')}')}" } + }, + { + "name": "Path", + "type": "PathChooser", + "trDisplayName": "Path:", + "mandatory": true, + "data": + { + "kind": "existingDirectory", + "basePath": "%{InitialPath}", + "path": "%{InitialPath}" + } + } + ] + }, + { + "trDisplayName": "Project Management", + "trShortTitle": "Summary", + "typeId": "Summary" + } + ], + + "generators": + [ + { + "typeId": "File", + "data": + [ + { + "source": "file.h", + "target": "%{HdrPath}", + "openInEditor": true, + "options": [ + { "key": "Cpp:License:FileName", "value": "%{HdrFileName}" }, + { "key": "Cpp:License:ClassName", "value": "%{CN}" } + ] + }, + { + "source": "file.cpp", + "target": "%{SrcPath}", + "openInEditor": true, + "options": [ + { "key": "Cpp:License:FileName", "value": "%{SrcFileName}" }, + { "key": "Cpp:License:ClassName", "value": "%{CN}" } + ] + }, + { + "source": "file.png", + "target": "%{TargetPath}/%{PluginBitmapName}.png", + "openInEditor": false, + "isBinary": true + } + ] + } + ] +}