void CElementManager::OnLButtonDown(CModeler1View* pView, UINT nFlags, const CPoint& cpoint)
{
    if( m_type == ElementType::type_unknown )
    {
        //FIXME : do we need to handle not implemented objects ?
        return;
    }
    
    CPoint point = cpoint;
    ViewToManager(pView, point);
    m_clickPoint = point;
    m_lastPoint = point;
    m_selectPoint = point;

    if( m_type == ElementType::type_select )
    {

        m_selectMode = SelectMode::none;

        // Check for resizing (only allowed on single selections)
        if( HasSelection() &&  m_selection.GetCount() == 1)
        {
            std::shared_ptr<CElement> pElement = m_selection.GetHead();
            //Change cursor look because mouse click is over an object for sizing 
            m_nDragHandle = pElement->HitTest(point, pView, TRUE);
            if (m_nDragHandle != 0)
            {
                m_selectMode = SelectMode::size;
                
                if (m_nDragHandle == 2)
                {
                    m_connectorInUse = ConnectorType::connector2;
                }
                else
                {
                    m_connectorInUse = ConnectorType::connector1;
                }
            }
            else
            {
                m_connectorInUse = ConnectorType::connector2;
            }
        }

        if( m_selectMode == SelectMode::none )
        {
            // See if the click was on an object
            std::shared_ptr<CElement> pElement = m_objects.ObjectAt(point, m_selectType);
            if( pElement != NULL )
            {
                if( IsSelected(pElement) == false )
                {
                    if( (nFlags & MK_SHIFT) || (nFlags & MK_CONTROL))
                    {
                    }
                    else
                        SelectNone();

                    if (pElement->m_bGrouping == false)
                    {
                        m_objectId = pElement->m_objectId;
                        Select(pElement);
                    }
                    else
                    {
                        for (vector<std::shared_ptr<CElement>>::const_iterator itSel = pElement->m_pElementGroup->m_Groups.begin(); itSel != pElement->m_pElementGroup->m_Groups.end(); itSel++)
                        {
                            std::shared_ptr<CElement> pObj = *itSel;
                            Select(pObj);
                        }
                    }

                    pElement->m_bMoving = true;
                }
                else
                {
                    // if shift or control i spressed, unselect the element
                    if ((nFlags & MK_SHIFT) || (nFlags & MK_CONTROL))
                    {
                        Deselect(pElement);
                    }
                }

                m_selectMode = SelectMode::move;

                // Update UI
                UpdateUI(pView, pElement);
                // Redraw
                Invalidate(pView, pElement);
            }
            else
            {
                // See if the click was on an object
                // TRUE -> select and start move if so
                // FALSE -> Click on background, start a net-selection
                // m_selectMode = netSelect;

                if( HasSelection() )
                {
                    SelectNone();
                    Invalidate(pView, pElement);
                }
                
                m_selectMode = SelectMode::netselect;
            }
        }
    }
    // We are not in a select operation
    // -> this is a drawing operation
    // We have to create...
    // Create a Drawable Object...
    else
    {

#ifdef VERSION_COMMUNITY
        if (CFactory::g_counter > MAX_SHAPES && IsMyLocalDev() == false)
        {
            AfxMessageBox(_T("Maximum number or shapes reached !\nFor more, please buy the Architect Edition."));
            return;
        }
#endif

        SelectNone();

        std::shared_ptr<CElement> pNewElement = CFactory::CreateElementOfType(m_type, m_shapeType);
        if( m_type == ElementType::type_unknown )
        {
            return;
        }

        if (m_shapeType == ShapeType::selection)
        {
            m_bSelectionHasStarted = true;
            pSelectionElement = pNewElement;
        }
        
        pNewElement->m_point = point;
        // For plumbing purpose...
        pNewElement->m_pManager = this;
        pNewElement->m_pView = pView;

        // Add an object
        m_objects.AddTail(pNewElement); 
        
        // Store last created object
        m_objectId = pNewElement->m_objectId;

        // Select the new element
        Select(pNewElement);

        m_selectMode = SelectMode::size;

        m_nDragHandle = 1;
        m_connectorInUse = ConnectorType::connector2;
        FindAConnectionFor(pNewElement, point, pView, ConnectorType::connector1);

        pView->GetDocument()->SetModifiedFlag();

        // Update ClassView & FileView
        UpdateClassView();//pNewElement);
        UpdateFileView();//pNewElement);

        // Update UI
        UpdateUI(pView, pNewElement);
    }

}

void CElementManager::OnMouseMove(CModeler1View* pView, UINT nFlags, const CPoint& cpoint)
{
    // a SELECT operation is started
    if( m_selectMode == SelectMode::none )
    {
    }
    
    CPoint point = cpoint;
    CPoint m_movePoint = point;
    ViewToManager(pView, point);
    CPoint lastPoint = point;

    std::shared_ptr<CElement> pElement = m_selection.GetHead(); //m_objects.FindElement(m_objectId);
    if( pElement == NULL )
    {
        return;
    }

    if( m_type == ElementType::type_select )
    {
        if( HasSelection() )
        {
            // Change cursor look temporary just because mouse could be over a shape
            int nHandle = pElement->HitTest(point, pView, true);
            if (nHandle != 0)
            {
                SetCursor(pElement->GetHandleCursor(nHandle));
            }

            if( m_selectMode == SelectMode::move )
            {
            
                for( vector<std::shared_ptr<CElement>>::const_iterator itSel = m_selection.m_objects.begin() ; itSel!=m_selection.m_objects.end() ; itSel++ )
                {
                    std::shared_ptr<CElement> pObj = *itSel;

                    CPoint delta = (CPoint)(point - m_lastPoint);       
                    InvalObj(pView, pObj);
                    pObj->m_rect += delta;
                    pObj->m_point = pObj->m_rect.TopLeft();
                    InvalObj(pView, pObj);
                }
                
                pView->GetDocument()->SetModifiedFlag();
            }

            if( m_selectMode == SelectMode::size )
            {
                if( m_nDragHandle != 0)
                {

                    std::shared_ptr<CElement> pObj = m_selection.GetHead();
                    pObj->MoveHandleTo(m_nDragHandle, point, pView);
                    FindAConnectionFor(pElement, point, pView, m_connectorInUse);
                    InvalObj(pView, pObj);

                    pView->GetDocument()->SetModifiedFlag();
                }
            }

        }
    }
    else
    {
        if( m_selectMode == SelectMode::size )
        {
            pElement->m_last = point;
            pElement->InvalidateObj();
            FindAConnectionFor(pElement, point, pView, m_connectorInUse);
            InvalObj(pView, pElement);

            pView->GetDocument()->SetModifiedFlag();
        }
    }   

    m_lastPoint = point;

    // Check for mouse cursor -> sizing/moving
    if( m_selectMode == SelectMode::size )
    {
        //if (m_nDragHandle != 0)
        {
            SetCursor(m_selection.GetHead()->GetHandleCursor(m_nDragHandle));
        }
    }

    if( m_type == ElementType::type_select && m_selection.GetCount() == 0)
    {
        SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
    }
}

void CElementManager::OnLButtonUp(CModeler1View* pView, UINT nFlags, const CPoint& cpoint)
{
    CPoint point = cpoint;
    ViewToManager(pView, point);

    //if( m_selectMode == SelectMode::move || m_selectMode == SelectMode::size )
    {
        // Selection Moving or Sizing is finished. 
        // Nothing to do.
        m_selectMode = SelectMode::none;
    }

    //m_bDrawing = FALSE;

    std::shared_ptr<CElement> pElement = m_objects.FindElement(m_objectId);
    if (pElement == NULL)
        return;

    if (m_type == ElementType::type_select)
    {
        if (HasSelection() && m_selection.GetCount() == 1)
        {
            // Nothing to do...
    }
    else
    {
        // Finish a drawing operation
        pElement->m_last = point;
        pElement->InvalidateObj();
        pElement->CheckForKeepingAMinimumSize();
        // Switch the view in Select Mode
        m_type = ElementType::type_select;
    }

    //
    // We are gonna end a slection rect...
    //

    if (m_bSelectionHasStarted == true)
    {
        CRect rect = pSelectionElement->m_rect;

        // remove the selection element from the objects list
        vector<std::shared_ptr<CElement>>::iterator pos;
        pos = find(m_objects.m_objects.begin(), m_objects.m_objects.end(), pSelectionElement);
        if (pos != m_objects.m_objects.end())
        {
            m_objects.m_objects.erase(pos);
        }

        // remove the selection element from the selection list
        vector<std::shared_ptr<CElement>>::iterator pos2;
        pos2 = find(m_selection.m_objects.begin(), m_selection.m_objects.end(), pSelectionElement);
        if (pos2 != m_selection.m_objects.end())
        {
            m_selection.m_objects.erase(pos2);
        }

        //ViewToManager(pView, rect);
        SelectNone();

        shared_ptr<CElement> pLastSelected = nullptr;
        vector<std::shared_ptr<CElement>> v = m_objects.ObjectsInRectEx(rect, m_selectType); // version Ex : do not select lines with full connector
        if (v.size() != 0)
        {
            for (std::shared_ptr<CElement> pElement : v)
            {
                if (IsSelected(pElement) == false)
                {
                    if (pElement->m_bGrouping == false)
                    {
                        Select(pElement);
                        pLastSelected = pElement;
                    }
                }
            }
        }

        if (pLastSelected != nullptr)
        {
            // Update UI
            UpdateUI(pView, pLastSelected);
        }

        pSelectionElement = nullptr;
        m_bSelectionHasStarted = false;
    }

    m_bSizingALine = false;

    // Set selectType to default
    m_selectType = SelectType::intuitive;
    m_connectorInUse = ConnectorType::connector2;
    m_bDrawRectForConnectionPoint = false;

    pElement->m_bMoving = FALSE;
    // Redraw
    InvalObj(pView, pElement);  

    m_selectMode = SelectMode::none;
    pView->GetDocument()->SetModifiedFlag();
    pView->GetDocument()->UpdateAllViews(pView);
}

#define OffsetShapes_Simple         0
#define OffsetShapes_Image          50
#define OffsetShapes_Infrastructure 100
#define OffsetShapes_Text           200
#define OffsetShapes_Development    300
#define OffsetShapes_Import         400
#define OffsetShapes_Planning       500
#define OffsetShapes_Connectors     520

enum ShapeType : int 
{
    // Simple
    line = OffsetShapes_Simple,
    line_right,
    rectangle,
    ellipse,
    rectangle_round,
    triangle,
    line_broken,
    line_broken_right,
    notimp_igloo,
    notimpl_multi_line,
    arrow_right,
    arrow_down,
    courbe1,
    courbe2,
    parenthese_left,
    parenthese_right,
    star,
    line2 = 18,
    line_right2,
    line_left_right,
    line_broken2,
    line_broken_right2,
    line_broken_left_right,
    curve,
    curve_right,
    curve_left_right,
    courbe2_bis,
    patate,
    curve_fuzzy,
    basic_rectangle = 30,
    basic_rectangle2,
    basic_rectangle3,
    basic_losange,
    basic_round_rectangle,
    basic_database = 42,
    // Image
    image_fixed = OffsetShapes_Image,
    image_scaled,
    // Infrastructure
    infrastructure_server_ad = OffsetShapes_Infrastructure,
    infrastructure_server,
    infrastructure_server_web,
    infrastructure_server_database,
    infrastructure_workstation,
    infrastructure_laptop,
    infrastructure_firewall,
    infrastructure_network,
    infrastructure_virtual_server,
    infrastructure_virtual_server_web,
    infrastructure_virtual_server_database,
    infrastructure_virtualization_server,
    infrastructure_server_ad_grey,
    infrastructure_server_grey,
    infrastructure_server_database_grey,
    infrastructure_server_farm,
    infrastructure_workstation_grey,
    infrastructure_laptop_grey,
    // Text
    text = OffsetShapes_Text,
    text_left,
    text_center,
    text_right,
    text_justify,
    // Development
    development_class = OffsetShapes_Development,
    development_interface,
    development_enumeration,
    development_package,
    development_comment,
    development_component,
    development_association,
    development_aggregation,
    development_composition,
    development_dependency,
    development_inheritance,
    development_package_import,
    development_connector,
    import_class = OffsetShapes_Import,
    planning_month = OffsetShapes_Planning,
    planning_task,
    selection,
    connection,
    diagram,
    connector_up = OffsetShapes_Connectors,
    connector_down,
    connector_left,
    connector_right,
    connector_single_left,
    connector_single_right,
    unknown = 1000
};

void CModeler1View::OnModelingShapes()
{
    // TODO: Add your command handler code here
    GetManager()->m_type = ElementType::type_shapes_simple;
    int shapeId = CMFCRibbonGallery::GetLastSelectedItem(ID_DESIGN_SHAPES);
    GetManager()->m_shapeType = CShapeType::ToShapeType(OffsetShapes_Simple + shapeId);
}

std::shared_ptr<CElement> pNewElement = 
    CFactory::CreateElementOfType(m_type, m_shapeType);
pNewElement->m_point = point;
// For plumbing purpose...
pNewElement->m_pManager = this;
pNewElement->m_pView = pView;
// Add an object
m_objects.AddTail(pNewElement);        
// Store last created object
m_objectId = pNewElement->m_objectId;
// Select the new element
Select(pNewElement);
m_selectMode = SelectMode::size;

Contenu du fichier sqlite.h :
#ifdef SQLITE_EXPORTS
#define SQLITE_API __declspec(dllexport)
#else
#define SQLITE_API __declspec(dllimport)
#endif

Contenu du fichier sqlite3.h :
../..
SQLITE_API int sqlite3_open(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);
SQLITE_API int sqlite3_open16(
  const void *filename,   /* Database filename (UTF-16) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);
SQLITE_API int sqlite3_open_v2(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb,         /* OUT: SQLite db handle */
  int flags,              /* Flags */
  const char *zVfs        /* Name of VFS module to use */
);
../…

   int sqlite3_user_authenticate(
     sqlite3 *db,           /* The database connection */
     const char *zUsername, /* Username */
     const char *aPW,       /* Password or credentials */
     int nPW                /* Number of bytes in aPW[] */
   );

#ifndef __Database_H__
#define __Database_H__

#include <sqlite/sqlite3.h>

namespace SQLite
{

    class Query;
    class PreparedStmt;

    class SQLITEWRAPPER_API Database
    {
    public:
        Database(void);
        Database(std::string filename);
        virtual ~Database(void);

    public:
        void SetDatabaseName(std::string fileName);
        void AddUser(std::string user, std::string password);
        bool AuthenticateUser(std::string user, std::string password);
        bool IsOpen();
        sqlite3_stmt* PrepareQuery(std::string query);
        void SetFileName(std::string filename);
        bool CreateAdminUser();
        bool Open();
        bool OpenEx(std::string user, std::string password);
        bool Close();
        void ReportError(std::string context);
        int ExecuteSQL(std::string sql, int& rows);
        int ExecuteCommand(std::string command, int& rows);
        Query ExecuteQuery(std::string query, int& rows);
        PreparedStmt CreatePreparedStmt(std::string statement);
        int ExecuteScalar(std::string query);
        sqlite_int64 GetLastRowID();
        void SetBusyTimeout(int timeout);
        sqlite_int64 InsertAndReturnID(std::string sqlinsert);

    protected:
        std::string m_DatabaseFileName;
        bool m_bOpen;
        sqlite3* m_instance;
    };

}
#endif //__Database_H__

Contenu de PreparedStmt.h :

#ifndef __PreparedStmt_H__
#define __PreparedStmt_H__

#include <sqlite/sqlite3.h>
#include <string>
#include "Query.h"

namespace SQLite
{

    class SQLITEWRAPPER_API PreparedStmt
    {
    public:
        PreparedStmt(void);
        PreparedStmt(sqlite3* instance, sqlite3_stmt* stmt);
        virtual ~PreparedStmt(void);

    public:
        PreparedStmt& operator=(const PreparedStmt& right);
        void SetStringParameter(int index, std::string value);
        void SetIntegerParameter(int index, int value);
        void SetDoubleParameter(int index, double value);
        void SetInt64Parameter(int index, sqlite_int64 value);
        void SetNullParameter(int index);
        void Reset();
        void Close();
        int Execute(int& rozs);
        sqlite_int64 ExecuteAndGetID();
        Query ExecuteAndGetQuery();

    protected:
        sqlite3_stmt* m_statement;
        sqlite3* m_instance;
        int m_NumberOfParameters;

    public:
        inline bool IsOpen() { return m_instance != NULL; }
        inline bool IsStmtOpen() { return m_statement != NULL; }
        inline void SetNull() { m_statement = NULL; }
        inline bool CheckParameter(int index) { return (index <= m_NumberOfParameters); };
        inline int  GetNumberOfParams() { return m_NumberOfParameters; }
    };

}

#endif //__PreparedStmt_H__

Contenu de Query.h :

#ifndef __Query_H__
#define __Query_H__

#include <string>
#include <sqlite/sqlite3.h>
#include "common/ColumnType.h"
#include "common/DatabaseException.h"

namespace SQLite
{

    class SQLITEWRAPPER_API Query
    {
    public:
        Query(void);
        virtual ~Query(void);
        Query(sqlite3_stmt* stmt, sqlite3* instance, bool norows, bool ownstatement = true);
        Query(const Query& query);
        Query& operator=(const Query& query);

    protected:
        sqlite3_stmt* m_statement;
        sqlite3* m_instance;
        int m_NbCols;
        bool m_bEOF;
        bool m_bDestroyStatement;

    protected:
        inline bool IsOpen() { return m_instance != NULL; }
        inline bool IsStmtOpen() { return m_statement != NULL; }
        inline void SetNull() { m_statement = NULL; }

    public:
        inline bool IsEOF() { return m_bEOF; }
        inline bool IsColumnIndexValid(int index) { return (((index >= 0) && (index <= (m_NbCols - 1)))); }
        inline int GetNumberOfColumns() { return m_NbCols; }
        void Close();
        std::string GetColumnName(int index);
        ColumnType GetColumnType(int index);
        double GetDoubleValue(int index);
        int GetIntValue(int index);
        long GetLongValue(int index);
        std::string GetStringValue(int index);
        void MoveNext();
    };

}

#endif //__Query_H__ 

	bool Database::OpenEx(std::string user, std::string password)
	{
		int retValue = sqlite3_open_v2(m_DatabaseFileName.c_str(), &m_instance, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
		m_bOpen = (retValue == SQLITE_OK);
		if (!m_bOpen)
		{
			ReportError(" opening database file " + m_DatabaseFileName + " ");
		}

		retValue = sqlite3_user_authenticate(m_instance, user.c_str(), password.c_str(), password.size());
		if (retValue == SQLITE_OK)
			return true;

		return false;
	}

	// open database
	SQLite::Database db;
	string dbName = UFM_SQLITE_DATABASE;
	db.SetDatabaseName(dbName);
	if (!db.OpenEx(UFM_SQLITE_USER, UFM_SQLITE_PASSWORD))
		return;

	// store to db
	SQLiteDiagramEntity diagramEntity(&db);
	diagramEntity.FileName = diagramName;
	diagramEntity.Json = strJson;
	diagramEntity.InsertOrUpdate(m_diagramId);
	db.Close();

bool SQLiteDiagramEntity::InsertOrUpdate(int& id)
{
    string sql;

    if (id == 0)
    {
        // Insert
        // "INSERT INTO Diagram VALUES (NULL, datetime('now'), ?, ?);"
        sql = SQLiteQueryString::GetSQLQuery(SQLiteQueryString::Insert_Diagram);

        SQLite::PreparedStmt stmt = m_pDatabase->CreatePreparedStmt(sql);
        stmt.SetStringParameter(1, this->FileName);
        stmt.SetStringParameter(2, this->Json);
        //stmt.SetNullParameter(6);

        int rows;
        if (!stmt.Execute(rows))
            return false;

        stmt.Close();

        id = m_pDatabase->GetLastRowID();
    }
    else
    {
        // Update
        // "UPDATE Diagram SET Json=? WHERE DiagramPK=?;"
        sql = SQLiteQueryString::GetSQLQuery(SQLiteQueryString::Update_Diagram);

        SQLite::PreparedStmt stmt = m_pDatabase->CreatePreparedStmt(sql);
        stmt.SetStringParameter(1, this->Json);
        stmt.SetIntegerParameter(2, id);
        //stmt.SetNullParameter(6);

        int rows;
        if (!stmt.Execute(rows))
            return false;

        stmt.Close();
    }

    return true;
}

vector<shared_ptr<SQLiteDiagramEntity>> SQLiteDiagramEntity::SelectAll()
{

    vector<shared_ptr<SQLiteDiagramEntity>> vDiagrams;
    string sql;

    try
    {
        // "SELECT DiagramPK, LastUpdate, FileName, Json FROM Diagram;"
        sql = SQLiteQueryString::GetSQLQuery(SQLiteQueryString::SelectAll_Diagram);
        int rows = 0;

        //SQLite::Query q;
        //q = m_pDatabase->ExecuteQuery("select count(*) from Diagram", rows);
        //int count = q.GetLongValue(0);
        //q.Close();

        rows = 0;
        SQLite::Query query;
        query = m_pDatabase->ExecuteQuery(sql, rows);

        while (query.IsEOF() == false)
        {
            shared_ptr<SQLiteDiagramEntity> sde = make_shared<SQLiteDiagramEntity>();

            sde->DiagramPK = query.GetLongValue(0);
            sde->LastUpdate = query.GetStringValue(1);
            sde->FileName = query.GetStringValue(2);
            sde->Json = query.GetStringValue(3);

            vDiagrams.push_back(sde);

            query.MoveNext();
        }

        query.Close();
    }
    catch (SQLite::DatabaseException ex)
    {
        std::cerr << ex.ToString() << std::endl;
    }

    return vDiagrams;
} 

 	

Christophe PICHAUD | Leader de Domaine NET chez Infeeny
christophep@cpixxi.com | www.windowscpp.com