<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: ndarr.hxx,v $
 * $Revision: 1.19 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _NDARR_HXX
#define _NDARR_HXX

#include <com/sun/star/embed/XEmbeddedObject.hpp>
#include <svtools/svarray.hxx>

#ifndef _BPARR_HXX
#include <bparr.hxx>
#endif
#include <ndtyp.hxx>

#include <svtools/embedhlp.hxx>
#include <vector>

class Graphic;
class GraphicObject;
class String;
class SwAttrSet;
class SfxItemSet;
class SwCntntNode;
class SwDoc;
class SwGrfFmtColl;
class SwGrfNode;
class SwHistory;
class SwNode;
class SwNodeIndex;
class SwNodeRange;
class SwOLENode;
class SwOutlineNodes;
class SwPaM;
class SwSection;
class SwSectionFmt;
class SwSectionNode;
class SwStartNode;
class SwTableBoxFmt;
class SwTableFmt;
class SwTableLine;
class SwTableLineFmt;
class SwTableNode;
class SwTblToTxtSaves;
class SwTxtFmtColl;
class SwTxtNode;
class SwUndoTblToTxt;
class SwUndoTxtToTbl;
struct SwPosition;

// --------------------
// class SwNodes
// --------------------

typedef SwNode * SwNodePtr;
typedef BOOL (*FnForEach_SwNodes)( const SwNodePtr&, void* pArgs );

SV_DECL_PTRARR_SORT( SwOutlineNodes, SwNodePtr, 0, 10 )

class SwNodes: private BigPtrArray
{
    friend class SwDoc;
    friend class SwNode;
    friend class SwNodeIndex;

    SwNodePtr operator[]( USHORT n ) const;
    SwNodePtr operator[]( int n ) const;

    SwNodeIndex* pRoot;                 // Liste aller Indizies auf Nodes

    // --> OD 2006-10-16 #137792#
    // - rename from <Insert(..)> to <InsertNode(..)>
    // - add 3rd optional parameter <bSyncNumberAndNumRule>
    void InsertNode( const SwNodePtr pNode,
                     const SwNodeIndex& rPos,
                     const bool bSyncNumberAndNumRule = true );
    void InsertNode( const SwNodePtr pNode,
                     ULONG nPos,
                     const bool bSyncNumberAndNumRule = true);
    // <--
//  void Remove( const SwNodeIndex& rPos, USHORT nLen = 1 );
//  void Remove( ULONG nPos, USHORT nLen = 1 );
//  BOOL Move( const SwIndex & rOldPos, const SwIndex & rNewPos );

    SwDoc* pMyDoc;                      // in diesem Doc ist das Nodes-Array

    SwNode *pEndOfPostIts, *pEndOfInserts,  // das sind die festen Bereiche
           *pEndOfAutotext, *pEndOfRedlines,
           *pEndOfContent;

    mutable SwOutlineNodes* pOutlineNds;        // Array aller GliederiungsNodes

    BOOL bInNodesDel : 1;               // falls rekursiv aufgerufen wird
                                        // Num/Outline nicht aktualisierem
    BOOL bInDelUpdOutl : 1;             // Flags fuers aktualisieren von Outl.
    BOOL bInDelUpdNum : 1;              // Flags fuers aktualisieren von Outl.

    // fuer dier Verwaltung der Indizies
    void RegisterIndex( SwNodeIndex& rIdx );
    void DeRegisterIndex( SwNodeIndex& rIdx );
    void RemoveNode( ULONG nDelPos, ULONG nLen, BOOL bDel );

    // Aktionen auf die Nodes
    void SectionUpDown( const SwNodeIndex & aStart, const SwNodeIndex & aEnd );
    void DelNodes( const SwNodeIndex& rStart, ULONG nCnt = 1 );

    void ChgNode( SwNodeIndex& rDelPos, ULONG nSize,
                  SwNodeIndex& rInsPos, BOOL bNewFrms );

    void UpdtOutlineIdx( const SwNode& );   // Update ab Node alle OutlineNodes

    void _CopyNodes( const SwNodeRange&, const SwNodeIndex&,
                    BOOL bNewFrms = TRUE, BOOL bTblInsDummyNode = FALSE ) const;
    void _DelDummyNodes( const SwNodeRange& rRg );

protected:
    SwNodes( SwDoc* pDoc );

public:
    ~SwNodes();

    SwNodePtr operator[]( ULONG n ) const
        { return (SwNodePtr)BigPtrArray::operator[] ( n ); }

//JP 29.09.97: impl. steht im ndindex.hxx - sollte moeglichst bald auf die
//              neue Schnittstelle angepasst werden
    inline SwNodePtr operator[]( const SwNodeIndex& rIdx ) const;

    ULONG Count() const { return BigPtrArray::Count(); }
    void ForEach( FnForEach_SwNodes fnForEach, void* pArgs = 0 )
    {
        BigPtrArray::ForEach( 0, BigPtrArray::Count(),
                                (FnForEach) fnForEach, pArgs );
    }
    void ForEach( ULONG nStt, ULONG nEnd, FnForEach_SwNodes fnForEach, void* pArgs = 0 )
    {
        BigPtrArray::ForEach( nStt, nEnd, (FnForEach) fnForEach, pArgs );
    }
    void ForEach( const SwNodeIndex& rStart, const SwNodeIndex& rEnd,
                    FnForEach_SwNodes fnForEach, void* pArgs = 0 );

    // eine noch leere Section
    SwNode& GetEndOfPostIts() const     { return *pEndOfPostIts; }
    // Section fuer alle Fussnoten
    SwNode& GetEndOfInserts() const     { return *pEndOfInserts; }
    // Section fuer alle Flys/Header/Footers
    SwNode& GetEndOfAutotext() const    { return *pEndOfAutotext; }
    // Section fuer alle Redlines
    SwNode& GetEndOfRedlines() const    { return *pEndOfRedlines; }
    // das ist der letzte EndNode einer SonderSection. Hier nach kommt nur
    // noch die normale ContentSection (also der BodyText)
    SwNode& GetEndOfExtras() const      { return *pEndOfRedlines; }
    // die normale ContentSection (also der BodyText)
    SwNode& GetEndOfContent() const     { return *pEndOfContent; }

    // ist das NodesArray das normale vom Doc? (nicht das UndoNds, .. )
    // Implementierung steht im doc.hxx (weil man dazu Doc kennen muss) !
    BOOL IsDocNodes() const;

    USHORT GetSectionLevel(const SwNodeIndex &rIndex) const;
    void Delete(const SwNodeIndex &rPos, ULONG nNodes = 1);

    BOOL _MoveNodes( const SwNodeRange&, SwNodes& rNodes, const SwNodeIndex&,
                BOOL bNewFrms = TRUE );
    void Move( SwPaM&, SwPosition&, SwNodes& rNodes, BOOL bSplitNd=TRUE );

    void _Copy( const SwNodeRange& rRg, const SwNodeIndex& rInsPos,
                BOOL bNewFrms = TRUE ) const
        {   _CopyNodes( rRg, rInsPos, bNewFrms ); }

    void SectionUp( SwNodeRange *);
    void SectionDown( SwNodeRange *pRange, SwStartNodeType = SwNormalStartNode );

    BOOL CheckNodesRange( const SwNodeIndex& rStt, const SwNodeIndex& rEnd ) const;

    void GoStartOfSection(SwNodeIndex *) const;
    void GoEndOfSection(SwNodeIndex *) const;

    SwCntntNode* GoNext(SwNodeIndex *) const;
    SwCntntNode* GoPrevious(SwNodeIndex *) const;

    //Gehe zum naechsten/vorherigen Cntnt/Tabellennode, fuer den
    //es LayoutFrames gibt, dabei Kopf-/Fusszeilen/Rahmen etc. nicht verlassen
    SwNode* GoNextWithFrm(SwNodeIndex *) const;
    SwNode* GoPreviousWithFrm(SwNodeIndex *) const;

    // zum naechsten Content-Node, der nicht geschuetzt oder versteckt ist
    // (beides auf FALSE ==> GoNext/GoPrevious!!!)
    SwCntntNode* GoNextSection( SwNodeIndex *, int bSkipHidden  = TRUE,
                                           int bSkipProtect = TRUE ) const;
    SwCntntNode* GoPrevSection( SwNodeIndex *, int bSkipHidden  = TRUE,
                                           int bSkipProtect = TRUE ) const;

    // erzeuge ein leere Section von Start und EndNode. Darf nur gerufen
    // werden, wenn eine neue Section mit Inhalt erzeugt werden soll.
    // Zum Beispiel bei den Filtern/Undo/...
    SwStartNode* MakeEmptySection( const SwNodeIndex& rIdx,
                                    SwStartNodeType = SwNormalStartNode );

    // die Impl. von "Make...Node" stehen in den angegebenen .ccx-Files
    SwTxtNode *MakeTxtNode( const SwNodeIndex & rWhere,
                            SwTxtFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 ); // in ndtxt.cxx
    SwStartNode* MakeTextSection( const SwNodeIndex & rWhere,
                            SwStartNodeType eSttNdTyp,
                            SwTxtFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 );

    SwGrfNode *MakeGrfNode( const SwNodeIndex & rWhere,
                            const String& rGrfName,
                            const String& rFltName,
                            const Graphic* pGraphic,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0,
                            BOOL bDelayed = FALSE );    // in ndgrf.cxx

    SwGrfNode *MakeGrfNode( const SwNodeIndex & rWhere,
                            const GraphicObject& rGrfObj,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 ); // in ndgrf.cxx

    SwOLENode *MakeOLENode( const SwNodeIndex & rWhere,
                            const svt::EmbeddedObjectRef&,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 ); // in ndole.cxx
    SwOLENode *MakeOLENode( const SwNodeIndex & rWhere,
                            const String &rName,
                            sal_Int64 nAspect,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr ); // in ndole.cxx

        // Array aller GliederiungsNodes;
    const SwOutlineNodes& GetOutLineNds() const;

    void UpdateOutlineNode( const SwNode&, BYTE nOldLevel, BYTE nNewLevel );
        // alle Nodes Updaten - Rule/Format-Aenderung
    void UpdateOutlineNode(SwNode & rNd);

        // fuege die Nodes fuer die Tabelle ein
        // wenn Lines angegeben, erzeuge die Matrix aus Lines & Boxen
        // ansonsten nur die Anzahl von Boxen.
    /* #109161#

       New parameter pAttrSet: If pAttrSet is non-null and contains an
       adjust item it is propagated to the table cells. If there is an
       adjust in pCntntTxtColl or pHeadlineTxtColl this adjust item
       overrides the item in pAttrSet.

     */
    SwTableNode* InsertTable( const SwNodeIndex& rNdIdx,
                        USHORT nBoxes, SwTxtFmtColl* pCntntTxtColl,
                        USHORT nLines = 0, USHORT nRepeat = 0,
                        SwTxtFmtColl* pHeadlineTxtColl = 0,
                        const SwAttrSet * pAttrSet = 0);

        // erzeuge aus dem makierten Bereich eine ausgeglichene Tabelle
    SwTableNode* TextToTable( const SwNodeRange& rRange, sal_Unicode cCh,
                                SwTableFmt* pTblFmt,
                                SwTableLineFmt* pLineFmt,
                                SwTableBoxFmt* pBoxFmt,
                                SwTxtFmtColl* pTxtColl,
                                SwUndoTxtToTbl* pUndo = 0 );
    //create a table from a vector of NodeRanges - API support
    SwTableNode* TextToTable( const std::vector< std::vector<SwNodeRange> >& rTableNodes,
                                SwTableFmt* pTblFmt,
                                SwTableLineFmt* pLineFmt,
                                SwTableBoxFmt* pBoxFmt,
                                SwTxtFmtColl* pTxtColl
                                /*, SwUndo... pUndo*/ );

        // erzeuge aus der Tabelle wieder normalen Text
    BOOL TableToText( const SwNodeRange& rRange, sal_Unicode cCh,
                        SwUndoTblToTxt* = 0 );
        // steht im untbl.cxx und darf nur vom Undoobject gerufen werden
    SwTableNode* UndoTableToText( ULONG nStt, ULONG nEnd,
                        const SwTblToTxtSaves& rSavedData );

        // fuege in der Line, vor der InsPos eine neue Box ein. Das Format
        // wird von der nachfolgenden (vorhergenden;wenn an Ende) genommen
        // in der Line muss schon eine Box vorhanden sein !
    BOOL InsBoxen( SwTableNode*, SwTableLine*, SwTableBoxFmt*,
                        // Formate fuer den TextNode der Box
                        SwTxtFmtColl*, const SfxItemSet* pAutoAttr,
                        USHORT nInsPos, USHORT nCnt = 1 );
        // Splittet eine Tabelle in der Grund-Zeile, in der der Index steht.
        // Alle GrundZeilen dahinter wandern in eine neue Tabelle/-Node.
        // Ist das Flag bCalcNewSize auf TRUE, wird fuer beide neuen Tabellen
        // die neue SSize aus dem Max der Boxen errechnet; vorrausgesetzt,
        // die SSize ist "absolut" gesetzt (LONG_MAX)
        // (Wird zur Zeit nur fuer den RTF-Parser benoetigt)
    SwTableNode* SplitTable( const SwNodeIndex& rPos, BOOL bAfter = TRUE,
                                BOOL bCalcNewSize = FALSE );
        // fuegt 2 Tabellen, die hintereinander stehen, wieder zusammen
    BOOL MergeTable( const SwNodeIndex& rPos, BOOL bWithPrev = TRUE,
                    USHORT nMode = 0, SwHistory* pHistory = 0 );

        // fuege eine neue SwSection ein
    SwSectionNode* InsertSection( const SwNodeIndex& rNdIdx,
                                SwSectionFmt& rSectionFmt,
                                const SwSection&,
                                const SwNodeIndex* pEnde,
                                BOOL bInsAtStart = TRUE,
                                BOOL bCreateFrms = TRUE );

        // in welchem Doc steht das Nodes-Array ?
            SwDoc* GetDoc()         { return pMyDoc; }
    const   SwDoc* GetDoc() const   { return pMyDoc; }

        // suche den vorhergehenden [/nachfolgenden ] ContentNode oder
        // TabellenNode mit Frames. Wird kein Ende angeben, dann wird mit
        // dem FrameIndex begonnen; ansonsten, wird mit dem vor rFrmIdx und
        // dem hintern pEnd die Suche gestartet. Sollte kein gueltiger Node
        // gefunden werden, wird 0 returnt. rFrmIdx zeigt auf dem Node mit
        // Frames
    SwNode* FindPrvNxtFrmNode( SwNodeIndex& rFrmIdx,
                                const SwNode* pEnd = 0 ) const;

    //-> #112139#
    SwNode * DocumentSectionStartNode(SwNode * pNode) const;
    SwNode * DocumentSectionEndNode(SwNode * pNode) const;
    //<- #112139#
private:
    // privater Constructor, weil nie kopiert werden darf !!
    SwNodes( const SwNodes & rNodes );
};

#endif
<commit_msg>INTEGRATION: CWS swlists01 (1.18.192); FILE MERGED 2008/05/14 12:41:50 od 1.18.192.3: #i86732# remove no longer needed code 2008/05/08 16:16:25 od 1.18.192.2: RESYNC: (1.18-1.19); FILE MERGED 2008/03/20 07:53:36 od 1.18.192.1: #i86732# class <SwNodes> 	 - refactoring: remove not needed private operators []<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: ndarr.hxx,v $
 * $Revision: 1.20 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _NDARR_HXX
#define _NDARR_HXX

#include <com/sun/star/embed/XEmbeddedObject.hpp>
#include <svtools/svarray.hxx>

#ifndef _BPARR_HXX
#include <bparr.hxx>
#endif
#include <ndtyp.hxx>

#include <svtools/embedhlp.hxx>
#include <vector>

class Graphic;
class GraphicObject;
class String;
class SwAttrSet;
class SfxItemSet;
class SwCntntNode;
class SwDoc;
class SwGrfFmtColl;
class SwGrfNode;
class SwHistory;
class SwNode;
class SwNodeIndex;
class SwNodeRange;
class SwOLENode;
class SwOutlineNodes;
class SwPaM;
class SwSection;
class SwSectionFmt;
class SwSectionNode;
class SwStartNode;
class SwTableBoxFmt;
class SwTableFmt;
class SwTableLine;
class SwTableLineFmt;
class SwTableNode;
class SwTblToTxtSaves;
class SwTxtFmtColl;
class SwTxtNode;
class SwUndoTblToTxt;
class SwUndoTxtToTbl;
struct SwPosition;

// --------------------
// class SwNodes
// --------------------

typedef SwNode * SwNodePtr;
typedef BOOL (*FnForEach_SwNodes)( const SwNodePtr&, void* pArgs );

SV_DECL_PTRARR_SORT( SwOutlineNodes, SwNodePtr, 0, 10 )

class SwNodes: private BigPtrArray
{
    friend class SwDoc;
    friend class SwNode;
    friend class SwNodeIndex;

    SwNodeIndex* pRoot;                 // Liste aller Indizies auf Nodes

    // --> OD 2008-05-14 #refactorlists# - removed <bSyncNumberAndNumRule>
    void InsertNode( const SwNodePtr pNode,
                     const SwNodeIndex& rPos );
    void InsertNode( const SwNodePtr pNode,
                     ULONG nPos );
    // <--

    SwDoc* pMyDoc;                      // in diesem Doc ist das Nodes-Array

    SwNode *pEndOfPostIts, *pEndOfInserts,  // das sind die festen Bereiche
           *pEndOfAutotext, *pEndOfRedlines,
           *pEndOfContent;

    mutable SwOutlineNodes* pOutlineNds;        // Array aller GliederiungsNodes

    BOOL bInNodesDel : 1;               // falls rekursiv aufgerufen wird
                                        // Num/Outline nicht aktualisierem
    BOOL bInDelUpdOutl : 1;             // Flags fuers aktualisieren von Outl.
    BOOL bInDelUpdNum : 1;              // Flags fuers aktualisieren von Outl.

    // fuer dier Verwaltung der Indizies
    void RegisterIndex( SwNodeIndex& rIdx );
    void DeRegisterIndex( SwNodeIndex& rIdx );
    void RemoveNode( ULONG nDelPos, ULONG nLen, BOOL bDel );

    // Aktionen auf die Nodes
    void SectionUpDown( const SwNodeIndex & aStart, const SwNodeIndex & aEnd );
    void DelNodes( const SwNodeIndex& rStart, ULONG nCnt = 1 );

    void ChgNode( SwNodeIndex& rDelPos, ULONG nSize,
                  SwNodeIndex& rInsPos, BOOL bNewFrms );

    void UpdtOutlineIdx( const SwNode& );   // Update ab Node alle OutlineNodes

    void _CopyNodes( const SwNodeRange&, const SwNodeIndex&,
                    BOOL bNewFrms = TRUE, BOOL bTblInsDummyNode = FALSE ) const;
    void _DelDummyNodes( const SwNodeRange& rRg );

protected:
    SwNodes( SwDoc* pDoc );

public:
    ~SwNodes();

    SwNodePtr operator[]( ULONG n ) const
        { return (SwNodePtr)BigPtrArray::operator[] ( n ); }

//JP 29.09.97: impl. steht im ndindex.hxx - sollte moeglichst bald auf die
//              neue Schnittstelle angepasst werden
    inline SwNodePtr operator[]( const SwNodeIndex& rIdx ) const;

    ULONG Count() const { return BigPtrArray::Count(); }
    void ForEach( FnForEach_SwNodes fnForEach, void* pArgs = 0 )
    {
        BigPtrArray::ForEach( 0, BigPtrArray::Count(),
                                (FnForEach) fnForEach, pArgs );
    }
    void ForEach( ULONG nStt, ULONG nEnd, FnForEach_SwNodes fnForEach, void* pArgs = 0 )
    {
        BigPtrArray::ForEach( nStt, nEnd, (FnForEach) fnForEach, pArgs );
    }
    void ForEach( const SwNodeIndex& rStart, const SwNodeIndex& rEnd,
                    FnForEach_SwNodes fnForEach, void* pArgs = 0 );

    // eine noch leere Section
    SwNode& GetEndOfPostIts() const     { return *pEndOfPostIts; }
    // Section fuer alle Fussnoten
    SwNode& GetEndOfInserts() const     { return *pEndOfInserts; }
    // Section fuer alle Flys/Header/Footers
    SwNode& GetEndOfAutotext() const    { return *pEndOfAutotext; }
    // Section fuer alle Redlines
    SwNode& GetEndOfRedlines() const    { return *pEndOfRedlines; }
    // das ist der letzte EndNode einer SonderSection. Hier nach kommt nur
    // noch die normale ContentSection (also der BodyText)
    SwNode& GetEndOfExtras() const      { return *pEndOfRedlines; }
    // die normale ContentSection (also der BodyText)
    SwNode& GetEndOfContent() const     { return *pEndOfContent; }

    // ist das NodesArray das normale vom Doc? (nicht das UndoNds, .. )
    // Implementierung steht im doc.hxx (weil man dazu Doc kennen muss) !
    BOOL IsDocNodes() const;

    USHORT GetSectionLevel(const SwNodeIndex &rIndex) const;
    void Delete(const SwNodeIndex &rPos, ULONG nNodes = 1);

    BOOL _MoveNodes( const SwNodeRange&, SwNodes& rNodes, const SwNodeIndex&,
                BOOL bNewFrms = TRUE );
    void Move( SwPaM&, SwPosition&, SwNodes& rNodes, BOOL bSplitNd=TRUE );

    void _Copy( const SwNodeRange& rRg, const SwNodeIndex& rInsPos,
                BOOL bNewFrms = TRUE ) const
        {   _CopyNodes( rRg, rInsPos, bNewFrms ); }

    void SectionUp( SwNodeRange *);
    void SectionDown( SwNodeRange *pRange, SwStartNodeType = SwNormalStartNode );

    BOOL CheckNodesRange( const SwNodeIndex& rStt, const SwNodeIndex& rEnd ) const;

    void GoStartOfSection(SwNodeIndex *) const;
    void GoEndOfSection(SwNodeIndex *) const;

    SwCntntNode* GoNext(SwNodeIndex *) const;
    SwCntntNode* GoPrevious(SwNodeIndex *) const;

    //Gehe zum naechsten/vorherigen Cntnt/Tabellennode, fuer den
    //es LayoutFrames gibt, dabei Kopf-/Fusszeilen/Rahmen etc. nicht verlassen
    SwNode* GoNextWithFrm(SwNodeIndex *) const;
    SwNode* GoPreviousWithFrm(SwNodeIndex *) const;

    // zum naechsten Content-Node, der nicht geschuetzt oder versteckt ist
    // (beides auf FALSE ==> GoNext/GoPrevious!!!)
    SwCntntNode* GoNextSection( SwNodeIndex *, int bSkipHidden  = TRUE,
                                           int bSkipProtect = TRUE ) const;
    SwCntntNode* GoPrevSection( SwNodeIndex *, int bSkipHidden  = TRUE,
                                           int bSkipProtect = TRUE ) const;

    // erzeuge ein leere Section von Start und EndNode. Darf nur gerufen
    // werden, wenn eine neue Section mit Inhalt erzeugt werden soll.
    // Zum Beispiel bei den Filtern/Undo/...
    SwStartNode* MakeEmptySection( const SwNodeIndex& rIdx,
                                    SwStartNodeType = SwNormalStartNode );

    // die Impl. von "Make...Node" stehen in den angegebenen .ccx-Files
    SwTxtNode *MakeTxtNode( const SwNodeIndex & rWhere,
                            SwTxtFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 ); // in ndtxt.cxx
    SwStartNode* MakeTextSection( const SwNodeIndex & rWhere,
                            SwStartNodeType eSttNdTyp,
                            SwTxtFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 );

    SwGrfNode *MakeGrfNode( const SwNodeIndex & rWhere,
                            const String& rGrfName,
                            const String& rFltName,
                            const Graphic* pGraphic,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0,
                            BOOL bDelayed = FALSE );    // in ndgrf.cxx

    SwGrfNode *MakeGrfNode( const SwNodeIndex & rWhere,
                            const GraphicObject& rGrfObj,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 ); // in ndgrf.cxx

    SwOLENode *MakeOLENode( const SwNodeIndex & rWhere,
                            const svt::EmbeddedObjectRef&,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr = 0 ); // in ndole.cxx
    SwOLENode *MakeOLENode( const SwNodeIndex & rWhere,
                            const String &rName,
                            sal_Int64 nAspect,
                            SwGrfFmtColl *pColl,
                            SwAttrSet* pAutoAttr ); // in ndole.cxx

        // Array aller GliederiungsNodes;
    const SwOutlineNodes& GetOutLineNds() const;

    void UpdateOutlineNode( const SwNode&, BYTE nOldLevel, BYTE nNewLevel );
        // alle Nodes Updaten - Rule/Format-Aenderung
    void UpdateOutlineNode(SwNode & rNd);

        // fuege die Nodes fuer die Tabelle ein
        // wenn Lines angegeben, erzeuge die Matrix aus Lines & Boxen
        // ansonsten nur die Anzahl von Boxen.
    /* #109161#

       New parameter pAttrSet: If pAttrSet is non-null and contains an
       adjust item it is propagated to the table cells. If there is an
       adjust in pCntntTxtColl or pHeadlineTxtColl this adjust item
       overrides the item in pAttrSet.

     */
    SwTableNode* InsertTable( const SwNodeIndex& rNdIdx,
                        USHORT nBoxes, SwTxtFmtColl* pCntntTxtColl,
                        USHORT nLines = 0, USHORT nRepeat = 0,
                        SwTxtFmtColl* pHeadlineTxtColl = 0,
                        const SwAttrSet * pAttrSet = 0);

        // erzeuge aus dem makierten Bereich eine ausgeglichene Tabelle
    SwTableNode* TextToTable( const SwNodeRange& rRange, sal_Unicode cCh,
                                SwTableFmt* pTblFmt,
                                SwTableLineFmt* pLineFmt,
                                SwTableBoxFmt* pBoxFmt,
                                SwTxtFmtColl* pTxtColl,
                                SwUndoTxtToTbl* pUndo = 0 );
    //create a table from a vector of NodeRanges - API support
    SwTableNode* TextToTable( const std::vector< std::vector<SwNodeRange> >& rTableNodes,
                                SwTableFmt* pTblFmt,
                                SwTableLineFmt* pLineFmt,
                                SwTableBoxFmt* pBoxFmt,
                                SwTxtFmtColl* pTxtColl
                                /*, SwUndo... pUndo*/ );

        // erzeuge aus der Tabelle wieder normalen Text
    BOOL TableToText( const SwNodeRange& rRange, sal_Unicode cCh,
                        SwUndoTblToTxt* = 0 );
        // steht im untbl.cxx und darf nur vom Undoobject gerufen werden
    SwTableNode* UndoTableToText( ULONG nStt, ULONG nEnd,
                        const SwTblToTxtSaves& rSavedData );

        // fuege in der Line, vor der InsPos eine neue Box ein. Das Format
        // wird von der nachfolgenden (vorhergenden;wenn an Ende) genommen
        // in der Line muss schon eine Box vorhanden sein !
    BOOL InsBoxen( SwTableNode*, SwTableLine*, SwTableBoxFmt*,
                        // Formate fuer den TextNode der Box
                        SwTxtFmtColl*, const SfxItemSet* pAutoAttr,
                        USHORT nInsPos, USHORT nCnt = 1 );
        // Splittet eine Tabelle in der Grund-Zeile, in der der Index steht.
        // Alle GrundZeilen dahinter wandern in eine neue Tabelle/-Node.
        // Ist das Flag bCalcNewSize auf TRUE, wird fuer beide neuen Tabellen
        // die neue SSize aus dem Max der Boxen errechnet; vorrausgesetzt,
        // die SSize ist "absolut" gesetzt (LONG_MAX)
        // (Wird zur Zeit nur fuer den RTF-Parser benoetigt)
    SwTableNode* SplitTable( const SwNodeIndex& rPos, BOOL bAfter = TRUE,
                                BOOL bCalcNewSize = FALSE );
        // fuegt 2 Tabellen, die hintereinander stehen, wieder zusammen
    BOOL MergeTable( const SwNodeIndex& rPos, BOOL bWithPrev = TRUE,
                    USHORT nMode = 0, SwHistory* pHistory = 0 );

        // fuege eine neue SwSection ein
    SwSectionNode* InsertSection( const SwNodeIndex& rNdIdx,
                                SwSectionFmt& rSectionFmt,
                                const SwSection&,
                                const SwNodeIndex* pEnde,
                                BOOL bInsAtStart = TRUE,
                                BOOL bCreateFrms = TRUE );

        // in welchem Doc steht das Nodes-Array ?
            SwDoc* GetDoc()         { return pMyDoc; }
    const   SwDoc* GetDoc() const   { return pMyDoc; }

        // suche den vorhergehenden [/nachfolgenden ] ContentNode oder
        // TabellenNode mit Frames. Wird kein Ende angeben, dann wird mit
        // dem FrameIndex begonnen; ansonsten, wird mit dem vor rFrmIdx und
        // dem hintern pEnd die Suche gestartet. Sollte kein gueltiger Node
        // gefunden werden, wird 0 returnt. rFrmIdx zeigt auf dem Node mit
        // Frames
    SwNode* FindPrvNxtFrmNode( SwNodeIndex& rFrmIdx,
                                const SwNode* pEnd = 0 ) const;

    //-> #112139#
    SwNode * DocumentSectionStartNode(SwNode * pNode) const;
    SwNode * DocumentSectionEndNode(SwNode * pNode) const;
    //<- #112139#
private:
    // privater Constructor, weil nie kopiert werden darf !!
    SwNodes( const SwNodes & rNodes );
};

#endif
<|endoftext|>


<commit_before>#include "shape/vertex.h"

#define rb_array_p(x) RB_TYPE_P(x, T_ARRAY)

VALUE sr_cVertex;

SR_SHAPE_GET(Vertex, vertex)
SR_SHAPE_CHECK(Vertex, vertex)

bool siren_vertex_install()
{
  SR_SHAPE_INIT(Vertex)
  rb_define_method(sr_cVertex, "initialize", RUBY_METHOD_FUNC(siren_vertex_init), -1);
  rb_define_method(sr_cVertex, "xyz",        RUBY_METHOD_FUNC(siren_vertex_xyz),  -1);
  rb_define_method(sr_cVertex, "to_a",       RUBY_METHOD_FUNC(siren_vertex_xyz),  -1);
  rb_define_method(sr_cVertex, "to_v",       RUBY_METHOD_FUNC(siren_vertex_to_v), -1);
  return true;
}

VALUE siren_vertex_init(int argc, VALUE* argv, VALUE self)
{
  VALUE* a;
  VALUE len;
  rb_scan_args(argc, argv, "*", &a, &len);

  Standard_Real x = 0.0, y = 0.0, z = 0.0;
  if (len > 0 && rb_array_p(a[0])) {
    gp_Pnt p = siren_ary_to_pnt(a[0]);
    x = p.X(); y = p.Y(); z = p.Z();
  }
  else {
    if (len >= 1) {
      if (FIXNUM_P(a[0]))
        x = DBL2NUM(a[0]);
      else if (RB_FLOAT_TYPE_P(a[0]))
        x = VALUE(a[0]);
    }
    if (len >= 2) {
      if (FIXNUM_P(a[1]))
        y = DBL2NUM(a[1]);
      else if (RB_FLOAT_TYPE_P(a[1]))
        y = VALUE(a[1]);
    }
    if (len >= 3) {
      if (FIXNUM_P(a[2]))
        z = DBL2NUM(a[2]);
      else if (RB_FLOAT_TYPE_P(a[2]))
        z = VALUE(a[2]);
    }
  }
  TopoDS_Vertex v = BRepBuilderAPI_MakeVertex(gp_Pnt(x, y, z));
  auto p = siren_shape_get(self);
  *p = v;
  return self;
}

VALUE siren_vertex_xyz(int argc, VALUE* argv, VALUE self)
{
  TopoDS_Vertex vertex = siren_vertex_get(self);
  return siren_pnt_to_ary(BRep_Tool::Pnt(vertex));
}

VALUE siren_vertex_to_v(int argc, VALUE* argv, VALUE self)
{
  TopoDS_Vertex vertex = siren_vertex_get(self);
  gp_Pnt p = BRep_Tool::Pnt(vertex);
  return siren_vec_new(p.X(), p.Y(), p.Z());
}
<commit_msg>Update Siren::Vertex#initialize method.<commit_after>#include "shape/vertex.h"

#define rb_array_p(x) RB_TYPE_P(x, T_ARRAY)

VALUE sr_cVertex;

SR_SHAPE_GET(Vertex, vertex)
SR_SHAPE_CHECK(Vertex, vertex)

bool siren_vertex_install()
{
  SR_SHAPE_INIT(Vertex)
  rb_define_method(sr_cVertex, "initialize", RUBY_METHOD_FUNC(siren_vertex_init), -1);
  rb_define_method(sr_cVertex, "xyz",        RUBY_METHOD_FUNC(siren_vertex_xyz),  -1);
  rb_define_method(sr_cVertex, "to_a",       RUBY_METHOD_FUNC(siren_vertex_xyz),  -1);
  rb_define_method(sr_cVertex, "to_v",       RUBY_METHOD_FUNC(siren_vertex_to_v), -1);
  return true;
}

VALUE siren_vertex_init(int argc, VALUE* argv, VALUE self)
{
  VALUE a, y, z;
  rb_scan_args(argc, argv, "12", &a, &y, &z);
  gp_Pnt pnt;
  if (argc == 1) {
    pnt = siren_ary_to_pnt(a);
  }
  else if (argc == 3) {
    pnt = gp_Pnt(NUM2DBL(a), NUM2DBL(y), NUM2DBL(z));
  }
  else {
    rb_raise(Qnil, "wrong number of arguments specified.");
  }
  TopoDS_Vertex v = BRepBuilderAPI_MakeVertex(pnt);
  auto p = siren_shape_get(self);
  *p = v;
  return self;
}

VALUE siren_vertex_xyz(int argc, VALUE* argv, VALUE self)
{
  TopoDS_Vertex vertex = siren_vertex_get(self);
  return siren_pnt_to_ary(BRep_Tool::Pnt(vertex));
}

VALUE siren_vertex_to_v(int argc, VALUE* argv, VALUE self)
{
  TopoDS_Vertex vertex = siren_vertex_get(self);
  gp_Pnt p = BRep_Tool::Pnt(vertex);
  return siren_vec_new(p.X(), p.Y(), p.Z());
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions Inc. 1990-2014.  All rights reserved
 */
//  TEST    Foundation::Memory
#include    "Stroika/Foundation/StroikaPreComp.h"

#include    "Stroika/Foundation/Containers/Mapping.h"
#include    "Stroika/Foundation/Debug/Assertions.h"
#include    "Stroika/Foundation/Debug/Trace.h"

#include    "Stroika/Foundation/Memory/AnyVariantValue.h"
#include    "Stroika/Foundation/Memory/Optional.h"
#include    "Stroika/Foundation/Memory/SharedByValue.h"

#include    "../TestHarness/SimpleClass.h"
#include    "../TestHarness/TestHarness.h"

using   namespace   Stroika;
using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Memory;

//TODO: DOES IT EVEN NEED TO BE SAID? THese tests are a bit sparse ;-)

namespace   {
    void    Test1_Optional ()
    {
        {
            Optional<int>   x;
            VerifyTestResult (x.IsMissing ());
            x = 1;
            VerifyTestResult (not x.IsMissing ());
            VerifyTestResult (x.IsPresent ());
            VerifyTestResult (*x == 1);
        }
        {
            // Careful about self-assignment
            Optional<int>   x;
            x = 3;
            x = max (*x, 1);
            VerifyTestResult (x == 3);
        }
    }
    void    Test2_SharedByValue ()
    {
    }
    void    Test_4_Optional_Of_Mapping_Copy_Problem_ ()
    {
        using   namespace   Stroika::Foundation::Memory;
        using   namespace   Stroika::Foundation::Containers;
        Mapping<int, float>  ml1, ml2;
        ml1 = ml2;

        Optional<Mapping<int, float>>  ol1, ol2;
        if (ol2.IsPresent ()) {
            ml1 = *ol2;
        }
        ol1 = ml1;
        Optional<Mapping<int, float>>  xxxx2 (ml1);

        // fails to compile prior to 2013-09-09
        Optional<Mapping<int, float>>  xxxx1 (ol1);
        // fails to compile prior to 2013-09-09
        ol1 = ol2;
    }
    void    Test_5_AnyVariantValue_ ()
    {
        {
            VerifyTestResult (AnyVariantValue ().empty ());
            VerifyTestResult (not AnyVariantValue (1).empty ());
            VerifyTestResult (not AnyVariantValue ("1").empty ());
            //VerifyTestResult (AnyVariantValue ("1").GetType () == typeid ("1"));  // not sure why this fails but not worthy worrying about yet
            VerifyTestResult (AnyVariantValue (1).As<int> () == 1);
        }
        {
            AnyVariantValue v;
            VerifyTestResult (v.empty ());
            v = AnyVariantValue (1);
            VerifyTestResult (not v.empty ());
            VerifyTestResult (v.GetType () == typeid (1));
            VerifyTestResult (v.As<int> () == 1);
            v = AnyVariantValue (L"a");
            //VerifyTestResult (v.GetType () == typeid (L"a")); // not sure why this fails but not worthy worrying about yet
            VerifyTestResult (not v.empty ());
            v.clear ();
            VerifyTestResult (v.empty ());
            VerifyTestResult (v.GetType () == typeid (void));
        }
        {
            struct JIM {
                int a;
            };
            AnyVariantValue v;
            VerifyTestResult (v.empty ());
            v = AnyVariantValue (JIM ());
            VerifyTestResult (v.GetType () == typeid (JIM));
        }
        {
            AnyVariantValue v;
            VerifyTestResult (v.empty ());
            v = AnyVariantValue (1);
            v = v;
            VerifyTestResult (v.GetType () == typeid (1));
            VerifyTestResult (v.As<int> () == 1);
            v = AnyVariantValue (v);
            VerifyTestResult (v.GetType () == typeid (1));
            VerifyTestResult (v.As<int> () == 1);
        }
        {
            static int nCopies = 0;
            struct Copyable {
                Copyable ()
                {
                    ++nCopies;
                }
                Copyable (const Copyable&)
                {
                    ++nCopies;
                }
                ~Copyable ()
                {
                    --nCopies;
                }
                const Copyable& operator= (const Copyable&) = delete;
            };
            {
                AnyVariantValue v;
                VerifyTestResult (v.empty ());
                v = AnyVariantValue (Copyable ());
                v = v;
                v = AnyVariantValue (AnyVariantValue (v));
                v = AnyVariantValue (AnyVariantValue (Copyable ()));
                VerifyTestResult (v.GetType () == typeid (Copyable));
            }
            VerifyTestResult (0 == nCopies);
        }
    }
}

namespace   {

    void    DoRegressionTests_ ()
    {
        Test1_Optional ();
        Test2_SharedByValue ();
        Test_4_Optional_Of_Mapping_Copy_Problem_ ();
        Test_5_AnyVariantValue_ ();
    }
}

int main (int argc, const char* argv[])
{
    Stroika::TestHarness::Setup ();
    Stroika::TestHarness::PrintPassOrFail (DoRegressionTests_);
    return EXIT_SUCCESS;
}

<commit_msg>added testOptionalOfThingNotCopyable()<commit_after>/*
 * Copyright(c) Sophist Solutions Inc. 1990-2014.  All rights reserved
 */
//  TEST    Foundation::Memory
#include    "Stroika/Foundation/StroikaPreComp.h"

#include    "Stroika/Foundation/Containers/Mapping.h"
#include    "Stroika/Foundation/Debug/Assertions.h"
#include    "Stroika/Foundation/Debug/Trace.h"

#include    "Stroika/Foundation/Memory/AnyVariantValue.h"
#include    "Stroika/Foundation/Memory/Optional.h"
#include    "Stroika/Foundation/Memory/SharedByValue.h"

#include    "../TestHarness/SimpleClass.h"
#include    "../TestHarness/TestHarness.h"

using   namespace   Stroika;
using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Memory;

//TODO: DOES IT EVEN NEED TO BE SAID? THese tests are a bit sparse ;-)

namespace   {
    void    Test1_Optional ()
    {
        {
            Optional<int>   x;
            VerifyTestResult (x.IsMissing ());
            x = 1;
            VerifyTestResult (not x.IsMissing ());
            VerifyTestResult (x.IsPresent ());
            VerifyTestResult (*x == 1);
        }
        {
            // Careful about self-assignment
            Optional<int>   x;
            x = 3;
            x = max (*x, 1);
            VerifyTestResult (x == 3);
        }
		auto testOptionalOfThingNotCopyable = [] () {
			struct NotCopyable {
				NotCopyable () {}
				NotCopyable (const NotCopyable&&) {}	// but is moveable!
				NotCopyable (const NotCopyable&) = delete;
				const NotCopyable& operator= (const NotCopyable&) = delete;
			};
			Optional<NotCopyable>	n1;
			VerifyTestResult (n1.IsMissing ());
			Optional<NotCopyable>	n2 (std::move (NotCopyable ()));	// use r-value reference to move
			VerifyTestResult (n2.IsPresent ());
		};
		testOptionalOfThingNotCopyable ();
    }
    void    Test2_SharedByValue ()
    {
    }
    void    Test_4_Optional_Of_Mapping_Copy_Problem_ ()
    {
        using   namespace   Stroika::Foundation::Memory;
        using   namespace   Stroika::Foundation::Containers;
        Mapping<int, float>  ml1, ml2;
        ml1 = ml2;

        Optional<Mapping<int, float>>  ol1, ol2;
        if (ol2.IsPresent ()) {
            ml1 = *ol2;
        }
        ol1 = ml1;
        Optional<Mapping<int, float>>  xxxx2 (ml1);

        // fails to compile prior to 2013-09-09
        Optional<Mapping<int, float>>  xxxx1 (ol1);
        // fails to compile prior to 2013-09-09
        ol1 = ol2;
    }
    void    Test_5_AnyVariantValue_ ()
    {
        {
            VerifyTestResult (AnyVariantValue ().empty ());
            VerifyTestResult (not AnyVariantValue (1).empty ());
            VerifyTestResult (not AnyVariantValue ("1").empty ());
            //VerifyTestResult (AnyVariantValue ("1").GetType () == typeid ("1"));  // not sure why this fails but not worthy worrying about yet
            VerifyTestResult (AnyVariantValue (1).As<int> () == 1);
        }
        {
            AnyVariantValue v;
            VerifyTestResult (v.empty ());
            v = AnyVariantValue (1);
            VerifyTestResult (not v.empty ());
            VerifyTestResult (v.GetType () == typeid (1));
            VerifyTestResult (v.As<int> () == 1);
            v = AnyVariantValue (L"a");
            //VerifyTestResult (v.GetType () == typeid (L"a")); // not sure why this fails but not worthy worrying about yet
            VerifyTestResult (not v.empty ());
            v.clear ();
            VerifyTestResult (v.empty ());
            VerifyTestResult (v.GetType () == typeid (void));
        }
        {
            struct JIM {
                int a;
            };
            AnyVariantValue v;
            VerifyTestResult (v.empty ());
            v = AnyVariantValue (JIM ());
            VerifyTestResult (v.GetType () == typeid (JIM));
        }
        {
            AnyVariantValue v;
            VerifyTestResult (v.empty ());
            v = AnyVariantValue (1);
            v = v;
            VerifyTestResult (v.GetType () == typeid (1));
            VerifyTestResult (v.As<int> () == 1);
            v = AnyVariantValue (v);
            VerifyTestResult (v.GetType () == typeid (1));
            VerifyTestResult (v.As<int> () == 1);
        }
        {
            static int nCopies = 0;
            struct Copyable {
                Copyable ()
                {
                    ++nCopies;
                }
                Copyable (const Copyable&)
                {
                    ++nCopies;
                }
                ~Copyable ()
                {
                    --nCopies;
                }
                const Copyable& operator= (const Copyable&) = delete;
            };
            {
                AnyVariantValue v;
                VerifyTestResult (v.empty ());
                v = AnyVariantValue (Copyable ());
                v = v;
                v = AnyVariantValue (AnyVariantValue (v));
                v = AnyVariantValue (AnyVariantValue (Copyable ()));
                VerifyTestResult (v.GetType () == typeid (Copyable));
            }
            VerifyTestResult (0 == nCopies);
        }
    }
}

namespace   {

    void    DoRegressionTests_ ()
    {
        Test1_Optional ();
        Test2_SharedByValue ();
        Test_4_Optional_Of_Mapping_Copy_Problem_ ();
        Test_5_AnyVariantValue_ ();
    }
}

int main (int argc, const char* argv[])
{
    Stroika::TestHarness::Setup ();
    Stroika::TestHarness::PrintPassOrFail (DoRegressionTests_);
    return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXQt - a lightweight, Qt based, desktop toolset
 * https://lxqt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Alexander Sokoloff <sokoloff.a@gmail.com>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "plugin.h"
#include "ilxqtpanelplugin.h"
#include "pluginsettings_p.h"
#include "lxqtpanel.h"
#include <QDebug>
#include <QProcessEnvironment>
#include <QStringList>
#include <QDir>
#include <QFileInfo>
#include <QPluginLoader>
#include <QGridLayout>
#include <QDialog>
#include <QEvent>
#include <QMenu>
#include <QMouseEvent>
#include <QApplication>
#include <QWindow>
#include <memory>

#include <LXQt/Settings>
#include <LXQt/Translator>
#include <XdgIcon>

// statically linked built-in plugins
#if defined(WITH_DESKTOPSWITCH_PLUGIN)
#include "../plugin-desktopswitch/desktopswitch.h" // desktopswitch
extern void * loadPluginTranslation_desktopswitch_helper;
#endif
#if defined(WITH_MAINMENU_PLUGIN)
#include "../plugin-mainmenu/lxqtmainmenu.h" // mainmenu
extern void * loadPluginTranslation_mainmenu_helper;
#endif
#if defined(WITH_QUICKLAUNCH_PLUGIN)
#include "../plugin-quicklaunch/lxqtquicklaunchplugin.h" // quicklaunch
extern void * loadPluginTranslation_quicklaunch_helper;
#endif
#if defined(WITH_SHOWDESKTOP_PLUGIN)
#include "../plugin-showdesktop/showdesktop.h" // showdesktop
extern void * loadPluginTranslation_showdesktop_helper;
#endif
#if defined(WITH_SPACER_PLUGIN)
#include "../plugin-spacer/spacer.h" // spacer
extern void * loadPluginTranslation_spacer_helper;
#endif
#if defined(WITH_STATUSNOTIFIER_PLUGIN)
#include "../plugin-statusnotifier/statusnotifier.h" // statusnotifier
extern void * loadPluginTranslation_statusnotifier_helper;
#endif
#if defined(WITH_TASKBAR_PLUGIN)
#include "../plugin-taskbar/lxqttaskbarplugin.h" // taskbar
extern void * loadPluginTranslation_taskbar_helper;
#endif
#if defined(WITH_TRAY_PLUGIN)
#include "../plugin-tray/lxqttrayplugin.h" // tray
extern void * loadPluginTranslation_tray_helper;
#endif
#if defined(WITH_WORLDCLOCK_PLUGIN)
#include "../plugin-worldclock/lxqtworldclock.h" // worldclock
extern void * loadPluginTranslation_worldclock_helper;
#endif

QColor Plugin::mMoveMarkerColor= QColor(255, 0, 0, 255);

/************************************************

 ************************************************/
Plugin::Plugin(const LXQt::PluginInfo &desktopFile, LXQt::Settings *settings, const QString &settingsGroup, LXQtPanel *panel) :
    QFrame(panel),
    mDesktopFile(desktopFile),
    mPluginLoader(0),
    mPlugin(0),
    mPluginWidget(0),
    mAlignment(AlignLeft),
    mPanel(panel)
{
    mSettings = PluginSettingsFactory::create(settings, settingsGroup);

    setWindowTitle(desktopFile.name());
    mName = desktopFile.name();

    QStringList dirs;
    dirs << QProcessEnvironment::systemEnvironment().value("LXQTPANEL_PLUGIN_PATH").split(":");
    dirs << PLUGIN_DIR;

    bool found = false;
    if(ILXQtPanelPluginLibrary const * pluginLib = findStaticPlugin(desktopFile.id()))
    {
        // this is a static plugin
        found = true;
        loadLib(pluginLib);
    }
    else {
        // this plugin is a dynamically loadable module
        QString baseName = QString("lib%1.so").arg(desktopFile.id());
        for(const QString &dirName : qAsConst(dirs))
        {
            QFileInfo fi(QDir(dirName), baseName);
            if (fi.exists())
            {
                found = true;
                if (loadModule(fi.absoluteFilePath()))
                    break;
            }
        }
    }

    if (!isLoaded())
    {
        if (!found)
            qWarning() << QString("Plugin %1 not found in the").arg(desktopFile.id()) << dirs;

        return;
    }

    setObjectName(mPlugin->themeId() + "Plugin");

    // plugin handle for easy context menu
    setProperty("NeedsHandle", mPlugin->flags().testFlag(ILXQtPanelPlugin::NeedsHandle));

    QString s = mSettings->value("alignment").toString();

    // Retrun default value
    if (s.isEmpty())
    {
        mAlignment = (mPlugin->flags().testFlag(ILXQtPanelPlugin::PreferRightAlignment)) ?
                    Plugin::AlignRight :
                    Plugin::AlignLeft;
    }
    else
    {
        mAlignment = (s.toUpper() == "RIGHT") ?
                    Plugin::AlignRight :
                    Plugin::AlignLeft;

    }

    if (mPluginWidget)
    {
        QGridLayout* layout = new QGridLayout(this);
        layout->setSpacing(0);
        layout->setContentsMargins(0, 0, 0, 0);
        setLayout(layout);
        layout->addWidget(mPluginWidget, 0, 0);
    }

    saveSettings();

    // delay the connection to settingsChanged to avoid conflicts
    // while the plugin is still being initialized
    connect(mSettings, &PluginSettings::settingsChanged,
            this, &Plugin::settingsChanged);
}

/************************************************

 ************************************************/
Plugin::~Plugin()
{
    delete mPlugin;
    delete mPluginLoader;
    delete mSettings;
}

void Plugin::setAlignment(Plugin::Alignment alignment)
{
    mAlignment = alignment;
    saveSettings();
}

/************************************************

 ************************************************/
namespace
{
    //helper types for static plugins storage & binary search
    typedef std::unique_ptr<ILXQtPanelPluginLibrary> plugin_ptr_t;
    typedef std::tuple<QString, plugin_ptr_t, void *> plugin_tuple_t;

    //NOTE: Please keep the plugins sorted by name while adding new plugins.
    //NOTE2: we need to reference some (dummy) symbol from (autogenerated) LXQtPluginTranslationLoader.cpp
    // to be not stripped (as unused/unreferenced) in static linking time
    static plugin_tuple_t const static_plugins[] = {
#if defined(WITH_DESKTOPSWITCH_PLUGIN)
        std::make_tuple(QLatin1String("desktopswitch"), plugin_ptr_t{new DesktopSwitchPluginLibrary}, loadPluginTranslation_desktopswitch_helper),// desktopswitch
#endif
#if defined(WITH_MAINMENU_PLUGIN)
        std::make_tuple(QLatin1String("mainmenu"), plugin_ptr_t{new LXQtMainMenuPluginLibrary}, loadPluginTranslation_mainmenu_helper),// mainmenu
#endif
#if defined(WITH_QUICKLAUNCH_PLUGIN)
        std::make_tuple(QLatin1String("quicklaunch"), plugin_ptr_t{new LXQtQuickLaunchPluginLibrary}, loadPluginTranslation_quicklaunch_helper),// quicklaunch
#endif
#if defined(WITH_SHOWDESKTOP_PLUGIN)
        std::make_tuple(QLatin1String("showdesktop"), plugin_ptr_t{new ShowDesktopLibrary}, loadPluginTranslation_showdesktop_helper),// showdesktop
#endif
#if defined(WITH_SPACER_PLUGIN)
        std::make_tuple(QLatin1String("spacer"), plugin_ptr_t{new SpacerPluginLibrary}, loadPluginTranslation_spacer_helper),// spacer
#endif
#if defined(WITH_STATUSNOTIFIER_PLUGIN)
        std::make_tuple(QLatin1String("statusnotifier"), plugin_ptr_t{new StatusNotifierLibrary}, loadPluginTranslation_statusnotifier_helper),// statusnotifier
#endif
#if defined(WITH_TASKBAR_PLUGIN)
        std::make_tuple(QLatin1String("taskbar"), plugin_ptr_t{new LXQtTaskBarPluginLibrary}, loadPluginTranslation_taskbar_helper),// taskbar
#endif
#if defined(WITH_TRAY_PLUGIN)
        std::make_tuple(QLatin1String("tray"), plugin_ptr_t{new LXQtTrayPluginLibrary}, loadPluginTranslation_tray_helper),// tray
#endif
#if defined(WITH_WORLDCLOCK_PLUGIN)
        std::make_tuple(QLatin1String("worldclock"), plugin_ptr_t{new LXQtWorldClockLibrary}, loadPluginTranslation_worldclock_helper),// worldclock
#endif
    };
    static constexpr plugin_tuple_t const * const plugins_begin = static_plugins;
    static constexpr plugin_tuple_t const * const plugins_end = static_plugins + sizeof (static_plugins) / sizeof (static_plugins[0]);

    struct assert_helper
    {
        assert_helper()
        {
            Q_ASSERT(std::is_sorted(plugins_begin, plugins_end
                        , [] (plugin_tuple_t const & p1, plugin_tuple_t const & p2) -> bool { return std::get<0>(p1) < std::get<0>(p2); }));
        }
    };
    static assert_helper h;
}

ILXQtPanelPluginLibrary const * Plugin::findStaticPlugin(const QString &libraryName)
{
    // find a static plugin library by name -> binary search
    plugin_tuple_t const * plugin = std::lower_bound(plugins_begin, plugins_end, libraryName
            , [] (plugin_tuple_t const & plugin, QString const & name) -> bool { return std::get<0>(plugin) < name; });
    if (plugins_end != plugin && libraryName == std::get<0>(*plugin))
        return std::get<1>(*plugin).get();
    return nullptr;
}

// load a plugin from a library
bool Plugin::loadLib(ILXQtPanelPluginLibrary const * pluginLib)
{
    ILXQtPanelPluginStartupInfo startupInfo;
    startupInfo.settings = mSettings;
    startupInfo.desktopFile = &mDesktopFile;
    startupInfo.lxqtPanel = mPanel;

    mPlugin = pluginLib->instance(startupInfo);
    if (!mPlugin)
    {
        qWarning() << QString("Can't load plugin \"%1\". Plugin can't build ILXQtPanelPlugin.").arg(mDesktopFile.id());
        return false;
    }

    mPluginWidget = mPlugin->widget();
    if (mPluginWidget)
    {
        mPluginWidget->setObjectName(mPlugin->themeId());
        watchWidgets(mPluginWidget);
    }
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    return true;
}

// load dynamic plugin from a *.so module
bool Plugin::loadModule(const QString &libraryName)
{
    mPluginLoader = new QPluginLoader(libraryName);

    if (!mPluginLoader->load())
    {
        qWarning() << mPluginLoader->errorString();
        return false;
    }

    QObject *obj = mPluginLoader->instance();
    if (!obj)
    {
        qWarning() << mPluginLoader->errorString();
        return false;
    }

    ILXQtPanelPluginLibrary* pluginLib= qobject_cast<ILXQtPanelPluginLibrary*>(obj);
    if (!pluginLib)
    {
        qWarning() << QString("Can't load plugin \"%1\". Plugin is not a ILXQtPanelPluginLibrary.").arg(mPluginLoader->fileName());
        delete obj;
        return false;
    }
    return loadLib(pluginLib);
}

/************************************************

 ************************************************/
void Plugin::watchWidgets(QObject * const widget)
{
    // the QWidget might not be fully constructed yet, but we can rely on the isWidgetType()
    if (!widget->isWidgetType())
        return;
    widget->installEventFilter(this);
    // watch also children (recursive)
    for (auto const & child : widget->children())
    {
        watchWidgets(child);
    }
}

/************************************************

 ************************************************/
void Plugin::unwatchWidgets(QObject * const widget)
{
    widget->removeEventFilter(this);
    // unwatch also children (recursive)
    for (auto const & child : widget->children())
    {
        unwatchWidgets(child);
    }
}

/************************************************

 ************************************************/
void Plugin::settingsChanged()
{
    mPlugin->settingsChanged();
}

/************************************************

 ************************************************/
void Plugin::saveSettings()
{
    mSettings->setValue("alignment", (mAlignment == AlignLeft) ? "Left" : "Right");
    mSettings->setValue("type", mDesktopFile.id());
    mSettings->sync();

}

/************************************************

 ************************************************/
void Plugin::contextMenuEvent(QContextMenuEvent * /*event*/)
{
    mPanel->showPopupMenu(this);
}

/************************************************

 ************************************************/
void Plugin::mousePressEvent(QMouseEvent *event)
{
    switch (event->button())
    {
    case Qt::LeftButton:
        mPlugin->activated(ILXQtPanelPlugin::Trigger);
        break;

    case Qt::MidButton:
        mPlugin->activated(ILXQtPanelPlugin::MiddleClick);
        break;

    default:
        break;
    }
}

/************************************************

 ************************************************/
void Plugin::mouseDoubleClickEvent(QMouseEvent*)
{
    mPlugin->activated(ILXQtPanelPlugin::DoubleClick);
}

/************************************************

 ************************************************/
void Plugin::showEvent(QShowEvent *)
{
    if (mPluginWidget)
        mPluginWidget->adjustSize();
}

/************************************************

 ************************************************/
QMenu *Plugin::popupMenu() const
{
    QString name = this->name().replace("&", "&&");
    QMenu* menu = new QMenu(windowTitle());

    if (mPlugin->flags().testFlag(ILXQtPanelPlugin::HaveConfigDialog))
    {
        QAction* configAction = new QAction(
            XdgIcon::fromTheme(QLatin1String("preferences-other")),
            tr("Configure \"%1\"").arg(name), menu);
        menu->addAction(configAction);
        connect(configAction, SIGNAL(triggered()), this, SLOT(showConfigureDialog()));
    }

    QAction* moveAction = new QAction(XdgIcon::fromTheme("transform-move"), tr("Move \"%1\"").arg(name), menu);
    menu->addAction(moveAction);
    connect(moveAction, SIGNAL(triggered()), this, SIGNAL(startMove()));

    menu->addSeparator();

    QAction* removeAction = new QAction(
        XdgIcon::fromTheme(QLatin1String("list-remove")),
        tr("Remove \"%1\"").arg(name), menu);
    menu->addAction(removeAction);
    connect(removeAction, SIGNAL(triggered()), this, SLOT(requestRemove()));

    return menu;
}

/************************************************

 ************************************************/
bool Plugin::isSeparate() const
{
   return mPlugin->isSeparate();
}

/************************************************

 ************************************************/
bool Plugin::isExpandable() const
{
    return mPlugin->isExpandable();
}

/************************************************

 ************************************************/
bool Plugin::eventFilter(QObject * /*watched*/, QEvent * event)
{
    switch (event->type())
    {
        case QEvent::DragLeave:
            emit dragLeft();
            break;
        case QEvent::ChildAdded:
            watchWidgets(dynamic_cast<QChildEvent *>(event)->child());
            break;
        case QEvent::ChildRemoved:
            unwatchWidgets(dynamic_cast<QChildEvent *>(event)->child());
            break;
        default:
            break;
    }
    return false;
}

/************************************************

 ************************************************/
void Plugin::realign()
{
    if (mPlugin)
        mPlugin->realign();
}

/************************************************

 ************************************************/
void Plugin::showConfigureDialog()
{
    if (!mConfigDialog)
        mConfigDialog = mPlugin->configureDialog();

    if (!mConfigDialog)
        return;

    connect(this, &Plugin::destroyed, mConfigDialog.data(), &QWidget::close);
    mPanel->willShowWindow(mConfigDialog);
    mConfigDialog->show();
    mConfigDialog->raise();
    mConfigDialog->activateWindow();

    WId wid = mConfigDialog->windowHandle()->winId();
    KWindowSystem::activateWindow(wid);
    KWindowSystem::setOnDesktop(wid, KWindowSystem::currentDesktop());
}

/************************************************

 ************************************************/
void Plugin::requestRemove()
{
    emit remove();
    deleteLater();
}
<commit_msg>Fix a FTBFS when some plugins are not built<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXQt - a lightweight, Qt based, desktop toolset
 * https://lxqt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Alexander Sokoloff <sokoloff.a@gmail.com>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "plugin.h"
#include "ilxqtpanelplugin.h"
#include "pluginsettings_p.h"
#include "lxqtpanel.h"

#include <KWindowSystem>

#include <QDebug>
#include <QProcessEnvironment>
#include <QStringList>
#include <QDir>
#include <QFileInfo>
#include <QPluginLoader>
#include <QGridLayout>
#include <QDialog>
#include <QEvent>
#include <QMenu>
#include <QMouseEvent>
#include <QApplication>
#include <QWindow>
#include <memory>

#include <LXQt/Settings>
#include <LXQt/Translator>
#include <XdgIcon>

// statically linked built-in plugins
#if defined(WITH_DESKTOPSWITCH_PLUGIN)
#include "../plugin-desktopswitch/desktopswitch.h" // desktopswitch
extern void * loadPluginTranslation_desktopswitch_helper;
#endif
#if defined(WITH_MAINMENU_PLUGIN)
#include "../plugin-mainmenu/lxqtmainmenu.h" // mainmenu
extern void * loadPluginTranslation_mainmenu_helper;
#endif
#if defined(WITH_QUICKLAUNCH_PLUGIN)
#include "../plugin-quicklaunch/lxqtquicklaunchplugin.h" // quicklaunch
extern void * loadPluginTranslation_quicklaunch_helper;
#endif
#if defined(WITH_SHOWDESKTOP_PLUGIN)
#include "../plugin-showdesktop/showdesktop.h" // showdesktop
extern void * loadPluginTranslation_showdesktop_helper;
#endif
#if defined(WITH_SPACER_PLUGIN)
#include "../plugin-spacer/spacer.h" // spacer
extern void * loadPluginTranslation_spacer_helper;
#endif
#if defined(WITH_STATUSNOTIFIER_PLUGIN)
#include "../plugin-statusnotifier/statusnotifier.h" // statusnotifier
extern void * loadPluginTranslation_statusnotifier_helper;
#endif
#if defined(WITH_TASKBAR_PLUGIN)
#include "../plugin-taskbar/lxqttaskbarplugin.h" // taskbar
extern void * loadPluginTranslation_taskbar_helper;
#endif
#if defined(WITH_TRAY_PLUGIN)
#include "../plugin-tray/lxqttrayplugin.h" // tray
extern void * loadPluginTranslation_tray_helper;
#endif
#if defined(WITH_WORLDCLOCK_PLUGIN)
#include "../plugin-worldclock/lxqtworldclock.h" // worldclock
extern void * loadPluginTranslation_worldclock_helper;
#endif

QColor Plugin::mMoveMarkerColor= QColor(255, 0, 0, 255);

/************************************************

 ************************************************/
Plugin::Plugin(const LXQt::PluginInfo &desktopFile, LXQt::Settings *settings, const QString &settingsGroup, LXQtPanel *panel) :
    QFrame(panel),
    mDesktopFile(desktopFile),
    mPluginLoader(0),
    mPlugin(0),
    mPluginWidget(0),
    mAlignment(AlignLeft),
    mPanel(panel)
{
    mSettings = PluginSettingsFactory::create(settings, settingsGroup);

    setWindowTitle(desktopFile.name());
    mName = desktopFile.name();

    QStringList dirs;
    dirs << QProcessEnvironment::systemEnvironment().value("LXQTPANEL_PLUGIN_PATH").split(":");
    dirs << PLUGIN_DIR;

    bool found = false;
    if(ILXQtPanelPluginLibrary const * pluginLib = findStaticPlugin(desktopFile.id()))
    {
        // this is a static plugin
        found = true;
        loadLib(pluginLib);
    }
    else {
        // this plugin is a dynamically loadable module
        QString baseName = QString("lib%1.so").arg(desktopFile.id());
        for(const QString &dirName : qAsConst(dirs))
        {
            QFileInfo fi(QDir(dirName), baseName);
            if (fi.exists())
            {
                found = true;
                if (loadModule(fi.absoluteFilePath()))
                    break;
            }
        }
    }

    if (!isLoaded())
    {
        if (!found)
            qWarning() << QString("Plugin %1 not found in the").arg(desktopFile.id()) << dirs;

        return;
    }

    setObjectName(mPlugin->themeId() + "Plugin");

    // plugin handle for easy context menu
    setProperty("NeedsHandle", mPlugin->flags().testFlag(ILXQtPanelPlugin::NeedsHandle));

    QString s = mSettings->value("alignment").toString();

    // Retrun default value
    if (s.isEmpty())
    {
        mAlignment = (mPlugin->flags().testFlag(ILXQtPanelPlugin::PreferRightAlignment)) ?
                    Plugin::AlignRight :
                    Plugin::AlignLeft;
    }
    else
    {
        mAlignment = (s.toUpper() == "RIGHT") ?
                    Plugin::AlignRight :
                    Plugin::AlignLeft;

    }

    if (mPluginWidget)
    {
        QGridLayout* layout = new QGridLayout(this);
        layout->setSpacing(0);
        layout->setContentsMargins(0, 0, 0, 0);
        setLayout(layout);
        layout->addWidget(mPluginWidget, 0, 0);
    }

    saveSettings();

    // delay the connection to settingsChanged to avoid conflicts
    // while the plugin is still being initialized
    connect(mSettings, &PluginSettings::settingsChanged,
            this, &Plugin::settingsChanged);
}

/************************************************

 ************************************************/
Plugin::~Plugin()
{
    delete mPlugin;
    delete mPluginLoader;
    delete mSettings;
}

void Plugin::setAlignment(Plugin::Alignment alignment)
{
    mAlignment = alignment;
    saveSettings();
}

/************************************************

 ************************************************/
namespace
{
    //helper types for static plugins storage & binary search
    typedef std::unique_ptr<ILXQtPanelPluginLibrary> plugin_ptr_t;
    typedef std::tuple<QString, plugin_ptr_t, void *> plugin_tuple_t;

    //NOTE: Please keep the plugins sorted by name while adding new plugins.
    //NOTE2: we need to reference some (dummy) symbol from (autogenerated) LXQtPluginTranslationLoader.cpp
    // to be not stripped (as unused/unreferenced) in static linking time
    static plugin_tuple_t const static_plugins[] = {
#if defined(WITH_DESKTOPSWITCH_PLUGIN)
        std::make_tuple(QLatin1String("desktopswitch"), plugin_ptr_t{new DesktopSwitchPluginLibrary}, loadPluginTranslation_desktopswitch_helper),// desktopswitch
#endif
#if defined(WITH_MAINMENU_PLUGIN)
        std::make_tuple(QLatin1String("mainmenu"), plugin_ptr_t{new LXQtMainMenuPluginLibrary}, loadPluginTranslation_mainmenu_helper),// mainmenu
#endif
#if defined(WITH_QUICKLAUNCH_PLUGIN)
        std::make_tuple(QLatin1String("quicklaunch"), plugin_ptr_t{new LXQtQuickLaunchPluginLibrary}, loadPluginTranslation_quicklaunch_helper),// quicklaunch
#endif
#if defined(WITH_SHOWDESKTOP_PLUGIN)
        std::make_tuple(QLatin1String("showdesktop"), plugin_ptr_t{new ShowDesktopLibrary}, loadPluginTranslation_showdesktop_helper),// showdesktop
#endif
#if defined(WITH_SPACER_PLUGIN)
        std::make_tuple(QLatin1String("spacer"), plugin_ptr_t{new SpacerPluginLibrary}, loadPluginTranslation_spacer_helper),// spacer
#endif
#if defined(WITH_STATUSNOTIFIER_PLUGIN)
        std::make_tuple(QLatin1String("statusnotifier"), plugin_ptr_t{new StatusNotifierLibrary}, loadPluginTranslation_statusnotifier_helper),// statusnotifier
#endif
#if defined(WITH_TASKBAR_PLUGIN)
        std::make_tuple(QLatin1String("taskbar"), plugin_ptr_t{new LXQtTaskBarPluginLibrary}, loadPluginTranslation_taskbar_helper),// taskbar
#endif
#if defined(WITH_TRAY_PLUGIN)
        std::make_tuple(QLatin1String("tray"), plugin_ptr_t{new LXQtTrayPluginLibrary}, loadPluginTranslation_tray_helper),// tray
#endif
#if defined(WITH_WORLDCLOCK_PLUGIN)
        std::make_tuple(QLatin1String("worldclock"), plugin_ptr_t{new LXQtWorldClockLibrary}, loadPluginTranslation_worldclock_helper),// worldclock
#endif
    };
    static constexpr plugin_tuple_t const * const plugins_begin = static_plugins;
    static constexpr plugin_tuple_t const * const plugins_end = static_plugins + sizeof (static_plugins) / sizeof (static_plugins[0]);

    struct assert_helper
    {
        assert_helper()
        {
            Q_ASSERT(std::is_sorted(plugins_begin, plugins_end
                        , [] (plugin_tuple_t const & p1, plugin_tuple_t const & p2) -> bool { return std::get<0>(p1) < std::get<0>(p2); }));
        }
    };
    static assert_helper h;
}

ILXQtPanelPluginLibrary const * Plugin::findStaticPlugin(const QString &libraryName)
{
    // find a static plugin library by name -> binary search
    plugin_tuple_t const * plugin = std::lower_bound(plugins_begin, plugins_end, libraryName
            , [] (plugin_tuple_t const & plugin, QString const & name) -> bool { return std::get<0>(plugin) < name; });
    if (plugins_end != plugin && libraryName == std::get<0>(*plugin))
        return std::get<1>(*plugin).get();
    return nullptr;
}

// load a plugin from a library
bool Plugin::loadLib(ILXQtPanelPluginLibrary const * pluginLib)
{
    ILXQtPanelPluginStartupInfo startupInfo;
    startupInfo.settings = mSettings;
    startupInfo.desktopFile = &mDesktopFile;
    startupInfo.lxqtPanel = mPanel;

    mPlugin = pluginLib->instance(startupInfo);
    if (!mPlugin)
    {
        qWarning() << QString("Can't load plugin \"%1\". Plugin can't build ILXQtPanelPlugin.").arg(mDesktopFile.id());
        return false;
    }

    mPluginWidget = mPlugin->widget();
    if (mPluginWidget)
    {
        mPluginWidget->setObjectName(mPlugin->themeId());
        watchWidgets(mPluginWidget);
    }
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    return true;
}

// load dynamic plugin from a *.so module
bool Plugin::loadModule(const QString &libraryName)
{
    mPluginLoader = new QPluginLoader(libraryName);

    if (!mPluginLoader->load())
    {
        qWarning() << mPluginLoader->errorString();
        return false;
    }

    QObject *obj = mPluginLoader->instance();
    if (!obj)
    {
        qWarning() << mPluginLoader->errorString();
        return false;
    }

    ILXQtPanelPluginLibrary* pluginLib= qobject_cast<ILXQtPanelPluginLibrary*>(obj);
    if (!pluginLib)
    {
        qWarning() << QString("Can't load plugin \"%1\". Plugin is not a ILXQtPanelPluginLibrary.").arg(mPluginLoader->fileName());
        delete obj;
        return false;
    }
    return loadLib(pluginLib);
}

/************************************************

 ************************************************/
void Plugin::watchWidgets(QObject * const widget)
{
    // the QWidget might not be fully constructed yet, but we can rely on the isWidgetType()
    if (!widget->isWidgetType())
        return;
    widget->installEventFilter(this);
    // watch also children (recursive)
    for (auto const & child : widget->children())
    {
        watchWidgets(child);
    }
}

/************************************************

 ************************************************/
void Plugin::unwatchWidgets(QObject * const widget)
{
    widget->removeEventFilter(this);
    // unwatch also children (recursive)
    for (auto const & child : widget->children())
    {
        unwatchWidgets(child);
    }
}

/************************************************

 ************************************************/
void Plugin::settingsChanged()
{
    mPlugin->settingsChanged();
}

/************************************************

 ************************************************/
void Plugin::saveSettings()
{
    mSettings->setValue("alignment", (mAlignment == AlignLeft) ? "Left" : "Right");
    mSettings->setValue("type", mDesktopFile.id());
    mSettings->sync();

}

/************************************************

 ************************************************/
void Plugin::contextMenuEvent(QContextMenuEvent * /*event*/)
{
    mPanel->showPopupMenu(this);
}

/************************************************

 ************************************************/
void Plugin::mousePressEvent(QMouseEvent *event)
{
    switch (event->button())
    {
    case Qt::LeftButton:
        mPlugin->activated(ILXQtPanelPlugin::Trigger);
        break;

    case Qt::MidButton:
        mPlugin->activated(ILXQtPanelPlugin::MiddleClick);
        break;

    default:
        break;
    }
}

/************************************************

 ************************************************/
void Plugin::mouseDoubleClickEvent(QMouseEvent*)
{
    mPlugin->activated(ILXQtPanelPlugin::DoubleClick);
}

/************************************************

 ************************************************/
void Plugin::showEvent(QShowEvent *)
{
    if (mPluginWidget)
        mPluginWidget->adjustSize();
}

/************************************************

 ************************************************/
QMenu *Plugin::popupMenu() const
{
    QString name = this->name().replace("&", "&&");
    QMenu* menu = new QMenu(windowTitle());

    if (mPlugin->flags().testFlag(ILXQtPanelPlugin::HaveConfigDialog))
    {
        QAction* configAction = new QAction(
            XdgIcon::fromTheme(QLatin1String("preferences-other")),
            tr("Configure \"%1\"").arg(name), menu);
        menu->addAction(configAction);
        connect(configAction, SIGNAL(triggered()), this, SLOT(showConfigureDialog()));
    }

    QAction* moveAction = new QAction(XdgIcon::fromTheme("transform-move"), tr("Move \"%1\"").arg(name), menu);
    menu->addAction(moveAction);
    connect(moveAction, SIGNAL(triggered()), this, SIGNAL(startMove()));

    menu->addSeparator();

    QAction* removeAction = new QAction(
        XdgIcon::fromTheme(QLatin1String("list-remove")),
        tr("Remove \"%1\"").arg(name), menu);
    menu->addAction(removeAction);
    connect(removeAction, SIGNAL(triggered()), this, SLOT(requestRemove()));

    return menu;
}

/************************************************

 ************************************************/
bool Plugin::isSeparate() const
{
   return mPlugin->isSeparate();
}

/************************************************

 ************************************************/
bool Plugin::isExpandable() const
{
    return mPlugin->isExpandable();
}

/************************************************

 ************************************************/
bool Plugin::eventFilter(QObject * /*watched*/, QEvent * event)
{
    switch (event->type())
    {
        case QEvent::DragLeave:
            emit dragLeft();
            break;
        case QEvent::ChildAdded:
            watchWidgets(dynamic_cast<QChildEvent *>(event)->child());
            break;
        case QEvent::ChildRemoved:
            unwatchWidgets(dynamic_cast<QChildEvent *>(event)->child());
            break;
        default:
            break;
    }
    return false;
}

/************************************************

 ************************************************/
void Plugin::realign()
{
    if (mPlugin)
        mPlugin->realign();
}

/************************************************

 ************************************************/
void Plugin::showConfigureDialog()
{
    if (!mConfigDialog)
        mConfigDialog = mPlugin->configureDialog();

    if (!mConfigDialog)
        return;

    connect(this, &Plugin::destroyed, mConfigDialog.data(), &QWidget::close);
    mPanel->willShowWindow(mConfigDialog);
    mConfigDialog->show();
    mConfigDialog->raise();
    mConfigDialog->activateWindow();

    WId wid = mConfigDialog->windowHandle()->winId();
    KWindowSystem::activateWindow(wid);
    KWindowSystem::setOnDesktop(wid, KWindowSystem::currentDesktop());
}

/************************************************

 ************************************************/
void Plugin::requestRemove()
{
    emit remove();
    deleteLater();
}
<|endoftext|>


<commit_before>#include <iostream>
#include <ctime>
#include <fstream>
#include <string>
#include <limits>

#include "../include/Game.h"
#include "../include/Common.h"
#include "../include/Console.h"

#include "../include/PlayerTypes/PlayerTypes.h"
#include "../include/EnemyTypes/EnemyTypes.h"

using namespace std;
using namespace Common;

// To avoid conflict with numeric_limits<streamsize>::max used in Game::GetChoice()
#ifdef max
#undef max
#endif

#define SKIP_TURN -2

void Game::MainMenu(){
    // Main menu. Loops until you start
    // a game or quit.
	    for (int choice=-1; choice!=0;){
        choice = GetChoice(MenuType::eMain);
        switch(choice){
			case 1:
           		StartGame();
				break;
			case 2:
				HowToPlay();
				break;
			case 0:
				break;
        }
    }
}

string Game::InitializePlayerName() {
	ClearScreen();
	string name;
	cout << "What is your name?"
		<< endl << endl
		<< "> ";

  cin.ignore();
	getline(cin,name); // Change to full name
	return name;
}

char Game::InitializePlayerGender() {
    char gender;
    do {
        ClearScreen();
        cout << "What is your gender (M or F)?"
            << endl << endl
            << "> ";

        cin >> gender;
        gender = toupper(gender);
    } while (gender != 'M' && gender != 'F');

    return gender;
}

int Game::InitializePlayerClass() {
	// Initializes the player's class through user choice.
	int player_class = 0;
	player_class = GetChoice(MenuType::ePlayerClass);
	SetPlayerClass(player_class);
	return player_class;
}

void Game::SetPlayerClass(int player_class) {
	// Sets the Player class according to player code given.
	switch (player_class) {
	case 1:
		// Player's class is a warrior.
		_Player = new Warrior;
		break;
	case 2:
		// Player's class is a rogue.
		_Player = new Rogue;
		break;
	case 3:
		// Player's class is a healer.
		_Player = new Healer;
		break;
	case 4:
		// Player's class is a debugger.
		// Used to easily defeat enemies. Only for development purposes.
		_Player = new Debugger;
		break;
	case 5:
		// You are Saitama.
		// Do I have to explain??
		_Player = new Saitama;
		break;
	default:
		// If input does not equal any of the cases, the default class is a warrior.
		_Player = new Warrior;
		break;
	}
}

void Game::SetPlayerData(){
	/* Data initialized in order of:
	* class code
	* name
	* level
	* experience
	* health
	* arrows
	* bombs
	* potions
	* whetstones
	* weaponstrength
	* coins
	*/

	ifstream ReadData;
	ReadData.open("data.txt");

	// Runs if user has never played the game before or data is not found.
	if (!ReadData) {
		ReadData.close();
		ofstream WriteData;
		WriteData.open("data.txt");

		WriteData << InitializePlayerClass() << endl
			<< InitializePlayerName() << endl
            << InitializePlayerGender() << endl
			<< 1 << endl
			<< 0 << endl
			<< 100 << endl
			<< 10 << endl
			<< 1 << endl
			<< 1 << endl
			<< 1 << endl
			<< 100 << endl
			<< 0;
		WriteData.close();
	}

	else {
		// Initializes player type from class code given in data.txt
		int player_class;
		ReadData >> player_class;
		SetPlayerClass(player_class);
		ReadData.close();
	}
}

void Game::SetEnemy(){
    // Generates a random integer to determine class of the enemy.
    // The abstract class Enemy is morphed with one of its child classes.

    EnemyType selector = EnemyType(rand()%etNumEnemyTypes);
    switch(selector){
	case etSlimeball:
	// Enemy is a slimeball.
	_Enemy = new Slimeball;
            break;
        case etCrab:
            // Enemy is a crab.
            _Enemy = new Crab;
            break;
        case etGiantCrab:
            // Enemy is a giant crab.
            _Enemy = new GiantCrab;
            break;
        case etSquid:
            // Enemy is a squid.
            _Enemy = new Squid;
            break;
        case etGiantSquid:
            // Enemy is a giant squid.
            _Enemy = new GiantSquid;
            break;
		case etLich:
			// Enemy is a Lich
			_Enemy = new Lich;
			break;
		case etMurloc:
			//Enemy is a Murloc
			_Enemy = new Murloc;
			break;
		case etPutnafer:
			// Enemy is a Putnafer
			_Enemy = new Putnafer;
			break;
        case etZombie:
            // Enemy is a Zombie
            _Enemy = new Zombie;
            break;
		case etVampire:
			// Enemy is a Vampire
			_Enemy = new Vampire;
			break;
		case etWerewolf:
			// Enemy is a Werewolf
			_Enemy = new Werewolf;
			break;
		case etGoblin:
			// Enemy is a Goblin
			_Enemy = new Goblin;
			break;
		case etGargoyle:
			// Enemy is a Goblin
			_Enemy = new Gargoyle;
			break;
		case etCerberus:
			// Enemy is a Cerberus
			_Enemy = new Cerberus;
			break;
		case etSkeleton:
			// Enemy is a Rat
			_Enemy = new Skeleton;
			break;
		case etSmallRat:
			// Enemy is a Small Rat
			_Enemy = new SmallRat;
			break;
        default:
            // If the above cases do not match the selector for any reason,
            // the enemy defaults on the crab class.
            _Enemy = new Crab;
            break;
    }
    // Simply prints that the enemy's class was encountered.
	cout << _Enemy->GetIntro() << endl;
	Sleep(SLEEP_MS);
	ColourPrint(_Enemy->GetName(), Console::DarkGrey);
    cout << " encountered!" << endl << endl;
    Sleep(SLEEP_MS);
}

bool Game::PlayAgain(){
    // Returns a bool value to determine if the player wants to play again.

    char choice;
    cout << "Keep going? (y/n)" << endl << endl;
    choice = (char)input();
    // Returns true if the player says yes (Y, y, 1).
    if (choice == 'y' || choice == 'Y' || choice == '1') return true;
    // Returns false otherwise, regardless of choice=='n'.
    return false;
}

void Game::Intermission(){
    // Saves game in case player unexpectedly quits (uses X instead of
    // in-game quit.
    _Player->SaveGame();

    // Loops until the player starts another battle or they quit (IsPlaying=false).
    for (int choice=0; IsPlaying;){
        ClearScreen();
        cout << "*--------- Intermission ----------* " << endl << endl;

	_Player->DisplayInventory();
        cout << "1) Start battle" << endl;
        cout << "2) Store" << endl;
        cout << "3) Gamble" << endl;
	cout << "4) Use Item" << endl;
        cout << "0) Quit" << endl << endl;

        choice = input();

        switch(choice){
        case 1:
            // Returns to StartGame()'s loop, calling Battle().
            return;
        case 2:
            // Goes to the store where the player can buy items.
            /// Currently in working progress.
            _Store.StoreFront(_Player);
            break;
        case 3:
            // Goes to the gambling arena.
            // _Player is passed in to add items won to the player inventory.
            _Gambling.Gamble(_Player);
            break;
	case 4:
	    _Player->UseItem();
	    _Player->SaveGame();
	    break;
        case 0:
            // Breaks the loop in StartGame(), going back to MainMenu().
            IsPlaying=false;
	    break;
        }
    }
}

void Game::StartGame(){
    // Starts the game by initializing values for a new game.

    // Seeds the random number generator for pseudo-random numbers.
    srand((unsigned int)time(NULL));
    IsPlaying=true;

    // SetPlayerData() initializes the variables in this end.
    ClearScreen();
    SetPlayerData();

	// This initializes the variables on the Player end.
    ClearScreen();
    _Player->SetPlayerData();

    // Loops while the game is still playing.
    // Alternates between battles and intermission (gambling, store, et)
    while(IsPlaying){
		Intermission();
		if (!IsPlaying)
			break;
		Battle();
    }

    // Saves the player's data to an external file before quitting.
    _Player->SaveGame();
}

void Game::Battle(){
    ClearScreen();
    // Uses random integers to determine class of the enemy.
    SetEnemy();

    // Loops the actual battle while playing.
    while(IsPlaying){
        ClearScreen();
        // Displays the name and health bar of the player and enemy.
        // The Enemy* argument is to display the enemy's
        // name. Explained more in _Player->DisplayHealthBar().
        _Player->DisplayHUD(_Enemy);
        _Enemy->DisplayHUD();

		int damagePlayer = _Player->Action();
        // Player's turn to attack Enemy or choose other action.

		if (damagePlayer != SKIP_TURN){
			_Enemy->TakeDamage(damagePlayer);
			// Pauses console and ignores user input for SLEEP_MS milliseconds.
        		Sleep(SLEEP_MS);
		}

        // Leaves battle if player chooses to.
        if (!IsPlaying){
            IsPlaying = true;
            return;
        }

        // Executes when the enemy's health is 0 or below.
        if (_Enemy->IsDead()){
            // Adds drops to player's inventory from defeated enemy.
            _Player->AddToInventory(_Enemy->GetDrops());
            // Adds points to player's experience.
            _Player->AddExperience(_Enemy->ReturnExperience());
			// Replenishes player's health for the next round.
			_Player->ReplenishHealth();

			// If player wants to battle again, it breaks the loop and uses tail recursion to play again.
            if (PlayAgain()) break;
            // Returns to StartGame()'s loop, and executes Intermission().
            return;
        }

        // Enemy's turn to attack player.
		if (damagePlayer != SKIP_TURN)
			_Player->TakeDamage(_Enemy->Action());
        Sleep(SLEEP_MS);

        // Executes when player's health is 0 or below.
        if (_Player->IsDead()){
            // Player loses the amount of experience points gained when you defeat the enemy.
            _Player->LoseExperience(_Enemy->ReturnExperience());
			// Replenishes player's health for the next round.
			_Player->ReplenishHealth();

			if (PlayAgain()) break;
            return;
        }
    }
    Battle();
}

void Game::HowToPlay() {

	GetChoice(MenuType::eHowToPlay);
}

int Game::GetChoice(MenuType menuType)
{
	DisplayMenu(menuType);
	int choice = -1;
	while (!(cin >> choice)) {
		cin.clear();
		cin.ignore(numeric_limits<streamsize>::max(), '\n');
		cout << "Invalid input.  Please try again.";
		Sleep(SLEEP_MS);
		DisplayMenu(menuType);
	}
	return choice;
}

void Game::DisplayMenu(MenuType menuType)
{
	ClearScreen();
	switch (menuType)
	{
	case Game::eMain:
		cout << "========== TURN-BASED FIGHTING GAME ==========" << endl << endl
			<< "1) Start Game" << endl
			<< "2) How to play" << endl
			<< "0) Exit" << endl << endl << "> ";
		break;
	case Game::ePlayerClass:
		cout << endl
			<< "Which class do you want to play as?" << endl
			<< "1) Warrior (high damage, low healing capabilities)" << endl
			<< "2) Rogue (moderate damage, moderate healing capabilities)" << endl
			<< "3) Healer (low damage, high healing capabilities)" << endl
			<< "4) Debugger (INFINITE DAMAGE!!!!)" << endl
			<< "5) Saitama (self-explanatory)" << endl
			<< endl << endl
			<< "> ";
		break;
	case Game::eHowToPlay:
		cout << "============== HOW TO PLAY ==============" << endl << endl
			<< "Turn is a turn-based RPG game." << endl
			<< "Create your character and start playing." << endl
			<< "For playing you have to choose what to do by typing" << endl
			<< "the corresponding number." << endl
			<< "You can perform actions and use items." << endl << endl
			<< "-- Actions --" << endl
			<< "Attack: Regular attack" << endl
			<< "Risk Attack: Attack deals more damage, but with a chance of missing" << endl
			<< "Heal: Restore an amount of your HP" << endl
			<< "Flee: Run away from battle" << endl << endl
			<< "-- Items --" << endl
			<< "Bombs: Deals 50HP to your opponent with no chance of missing" << endl
			<< "Arrows: Deals 10-15HP to your opponent with no chance of missing" << endl
			<< "Potion: Replenishes your HP to 100" << endl
			<< "Whetstone: Restores your weapon's sharpness." << endl << endl
			<< "Good luck and have fun!" << endl << endl
			<< "0) Quit" << endl << endl << "> ";
		break;
	default:
		break;
	}
}
<commit_msg>Update Game.cpp<commit_after>#include <iostream>
#include <ctime>
#include <fstream>
#include <string>
#include <limits>

#include "../include/Game.h"
#include "../include/Common.h"
#include "../include/Console.h"

#include "../include/PlayerTypes/PlayerTypes.h"
#include "../include/EnemyTypes/EnemyTypes.h"

using namespace std;
using namespace Common;

// To avoid conflict with numeric_limits<streamsize>::max used in Game::GetChoice()
#ifdef max
#undef max
#endif

#define SKIP_TURN -2

void Game::MainMenu(){
    // Main menu. Loops until you start
    // a game or quit.
	    for (int choice=-1; choice!=0;){
        choice = GetChoice(MenuType::eMain);
        switch(choice){
			case 1:
           		StartGame();
				break;
			case 2:
				HowToPlay();
				break;
			case 0:
				break;
        }
    }
}

string Game::InitializePlayerName() {
	ClearScreen();
	string name;
	cout << "What is your name?"
		<< endl << endl
		<< "> ";

  cin.ignore();
	getline(cin,name); // Change to full name
	return name;
}

char Game::InitializePlayerGender() {
    char gender;
    do {
        ClearScreen();
        cout << "What is your gender (M or F)?"
            << endl << endl
            << "> ";

        cin >> gender;
        gender = toupper(gender);
    } while (gender != 'M' && gender != 'F');

    return gender;
}

int Game::InitializePlayerClass() {
	// Initializes the player's class through user choice.
	int player_class = 0;
	player_class = GetChoice(MenuType::ePlayerClass);
	SetPlayerClass(player_class);
	return player_class;
}

void Game::SetPlayerClass(int player_class) {
	// Sets the Player class according to player code given.
	switch (player_class) {
	case 1:
		// Player's class is a warrior.
		_Player = new Warrior;
		break;
	case 2:
		// Player's class is a rogue.
		_Player = new Rogue;
		break;
	case 3:
		// Player's class is a healer.
		_Player = new Healer;
		break;
	case 4:
		// Player's class is a debugger.
		// Used to easily defeat enemies. Only for development purposes.
		_Player = new Debugger;
		break;
	case 5:
		// You are Saitama.
		// Do I have to explain??
		_Player = new Saitama;
		break;
	default:
		// If input does not equal any of the cases, the default class is a warrior.
		_Player = new Warrior;
		break;
	}
}

void Game::SetPlayerData(){
	/* Data initialized in order of:
	* class code
	* name
	* level
	* experience
	* health
	* arrows
	* bombs
	* potions
	* whetstones
	* weaponstrength
	* coins
	*/

	ifstream ReadData;
	ReadData.open("data.txt");

	// Runs if user has never played the game before or data is not found.
	if (!ReadData) {
		ReadData.close();
		ofstream WriteData;
		WriteData.open("data.txt");

		WriteData << InitializePlayerClass() << endl
			<< InitializePlayerName() << endl
            << InitializePlayerGender() << endl
			<< 1 << endl
			<< 0 << endl
			<< 100 << endl
			<< 10 << endl
			<< 1 << endl
			<< 1 << endl
			<< 1 << endl
			<< 100 << endl
			<< 0;
		WriteData.close();
	}

	else {
		// Initializes player type from class code given in data.txt
		int player_class;
		ReadData >> player_class;
		SetPlayerClass(player_class);
		ReadData.close();
	}
}

void Game::SetEnemy(){
    // Generates a random integer to determine class of the enemy.
    // The abstract class Enemy is morphed with one of its child classes.

    EnemyType selector = EnemyType(rand()%etNumEnemyTypes);
    switch(selector){
	case etSlimeball:
	    // Enemy is a slimeball.
	    _Enemy = new Slimeball;
            break;
        case etCrab:
            // Enemy is a crab.
            _Enemy = new Crab;
            break;
        case etGiantCrab:
            // Enemy is a giant crab.
            _Enemy = new GiantCrab;
            break;
        case etSquid:
            // Enemy is a squid.
            _Enemy = new Squid;
            break;
        case etGiantSquid:
            // Enemy is a giant squid.
            _Enemy = new GiantSquid;
            break;
		case etLich:
			// Enemy is a Lich
			_Enemy = new Lich;
			break;
		case etMurloc:
			//Enemy is a Murloc
			_Enemy = new Murloc;
			break;
		case etPutnafer:
			// Enemy is a Putnafer
			_Enemy = new Putnafer;
			break;
        case etZombie:
            // Enemy is a Zombie
            _Enemy = new Zombie;
            break;
		case etVampire:
			// Enemy is a Vampire
			_Enemy = new Vampire;
			break;
		case etWerewolf:
			// Enemy is a Werewolf
			_Enemy = new Werewolf;
			break;
		case etGoblin:
			// Enemy is a Goblin
			_Enemy = new Goblin;
			break;
		case etGargoyle:
			// Enemy is a Goblin
			_Enemy = new Gargoyle;
			break;
		case etCerberus:
			// Enemy is a Cerberus
			_Enemy = new Cerberus;
			break;
		case etSkeleton:
			// Enemy is a Rat
			_Enemy = new Skeleton;
			break;
		case etSmallRat:
			// Enemy is a Small Rat
			_Enemy = new SmallRat;
			break;
        default:
            // If the above cases do not match the selector for any reason,
            // the enemy defaults on the crab class.
            _Enemy = new Crab;
            break;
    }
    // Simply prints that the enemy's class was encountered.
	cout << _Enemy->GetIntro() << endl;
	Sleep(SLEEP_MS);
	ColourPrint(_Enemy->GetName(), Console::DarkGrey);
    cout << " encountered!" << endl << endl;
    Sleep(SLEEP_MS);
}

bool Game::PlayAgain(){
    // Returns a bool value to determine if the player wants to play again.

    char choice;
    cout << "Keep going? (y/n)" << endl << endl;
    choice = (char)input();
    // Returns true if the player says yes (Y, y, 1).
    if (choice == 'y' || choice == 'Y' || choice == '1') return true;
    // Returns false otherwise, regardless of choice=='n'.
    return false;
}

void Game::Intermission(){
    // Saves game in case player unexpectedly quits (uses X instead of
    // in-game quit.
    _Player->SaveGame();

    // Loops until the player starts another battle or they quit (IsPlaying=false).
    for (int choice=0; IsPlaying;){
        ClearScreen();
        cout << "*--------- Intermission ----------* " << endl << endl;

	_Player->DisplayInventory();
        cout << "1) Start battle" << endl;
        cout << "2) Store" << endl;
        cout << "3) Gamble" << endl;
	cout << "4) Use Item" << endl;
        cout << "0) Quit" << endl << endl;

        choice = input();

        switch(choice){
        case 1:
            // Returns to StartGame()'s loop, calling Battle().
            return;
        case 2:
            // Goes to the store where the player can buy items.
            /// Currently in working progress.
            _Store.StoreFront(_Player);
            break;
        case 3:
            // Goes to the gambling arena.
            // _Player is passed in to add items won to the player inventory.
            _Gambling.Gamble(_Player);
            break;
	case 4:
	    _Player->UseItem();
	    _Player->SaveGame();
	    break;
        case 0:
            // Breaks the loop in StartGame(), going back to MainMenu().
            IsPlaying=false;
	    break;
        }
    }
}

void Game::StartGame(){
    // Starts the game by initializing values for a new game.

    // Seeds the random number generator for pseudo-random numbers.
    srand((unsigned int)time(NULL));
    IsPlaying=true;

    // SetPlayerData() initializes the variables in this end.
    ClearScreen();
    SetPlayerData();

	// This initializes the variables on the Player end.
    ClearScreen();
    _Player->SetPlayerData();

    // Loops while the game is still playing.
    // Alternates between battles and intermission (gambling, store, et)
    while(IsPlaying){
		Intermission();
		if (!IsPlaying)
			break;
		Battle();
    }

    // Saves the player's data to an external file before quitting.
    _Player->SaveGame();
}

void Game::Battle(){
    ClearScreen();
    // Uses random integers to determine class of the enemy.
    SetEnemy();

    // Loops the actual battle while playing.
    while(IsPlaying){
        ClearScreen();
        // Displays the name and health bar of the player and enemy.
        // The Enemy* argument is to display the enemy's
        // name. Explained more in _Player->DisplayHealthBar().
        _Player->DisplayHUD(_Enemy);
        _Enemy->DisplayHUD();

		int damagePlayer = _Player->Action();
        // Player's turn to attack Enemy or choose other action.

		if (damagePlayer != SKIP_TURN){
			_Enemy->TakeDamage(damagePlayer);
			// Pauses console and ignores user input for SLEEP_MS milliseconds.
        		Sleep(SLEEP_MS);
		}

        // Leaves battle if player chooses to.
        if (!IsPlaying){
            IsPlaying = true;
            return;
        }

        // Executes when the enemy's health is 0 or below.
        if (_Enemy->IsDead()){
            // Adds drops to player's inventory from defeated enemy.
            _Player->AddToInventory(_Enemy->GetDrops());
            // Adds points to player's experience.
            _Player->AddExperience(_Enemy->ReturnExperience());
			// Replenishes player's health for the next round.
			_Player->ReplenishHealth();

			// If player wants to battle again, it breaks the loop and uses tail recursion to play again.
            if (PlayAgain()) break;
            // Returns to StartGame()'s loop, and executes Intermission().
            return;
        }

        // Enemy's turn to attack player.
		if (damagePlayer != SKIP_TURN)
			_Player->TakeDamage(_Enemy->Action());
        Sleep(SLEEP_MS);

        // Executes when player's health is 0 or below.
        if (_Player->IsDead()){
            // Player loses the amount of experience points gained when you defeat the enemy.
            _Player->LoseExperience(_Enemy->ReturnExperience());
			// Replenishes player's health for the next round.
			_Player->ReplenishHealth();

			if (PlayAgain()) break;
            return;
        }
    }
    Battle();
}

void Game::HowToPlay() {

	GetChoice(MenuType::eHowToPlay);
}

int Game::GetChoice(MenuType menuType)
{
	DisplayMenu(menuType);
	int choice = -1;
	while (!(cin >> choice)) {
		cin.clear();
		cin.ignore(numeric_limits<streamsize>::max(), '\n');
		cout << "Invalid input.  Please try again.";
		Sleep(SLEEP_MS);
		DisplayMenu(menuType);
	}
	return choice;
}

void Game::DisplayMenu(MenuType menuType)
{
	ClearScreen();
	switch (menuType)
	{
	case Game::eMain:
		cout << "========== TURN-BASED FIGHTING GAME ==========" << endl << endl
			<< "1) Start Game" << endl
			<< "2) How to play" << endl
			<< "0) Exit" << endl << endl << "> ";
		break;
	case Game::ePlayerClass:
		cout << endl
			<< "Which class do you want to play as?" << endl
			<< "1) Warrior (high damage, low healing capabilities)" << endl
			<< "2) Rogue (moderate damage, moderate healing capabilities)" << endl
			<< "3) Healer (low damage, high healing capabilities)" << endl
			<< "4) Debugger (INFINITE DAMAGE!!!!)" << endl
			<< "5) Saitama (self-explanatory)" << endl
			<< endl << endl
			<< "> ";
		break;
	case Game::eHowToPlay:
		cout << "============== HOW TO PLAY ==============" << endl << endl
			<< "Turn is a turn-based RPG game." << endl
			<< "Create your character and start playing." << endl
			<< "For playing you have to choose what to do by typing" << endl
			<< "the corresponding number." << endl
			<< "You can perform actions and use items." << endl << endl
			<< "-- Actions --" << endl
			<< "Attack: Regular attack" << endl
			<< "Risk Attack: Attack deals more damage, but with a chance of missing" << endl
			<< "Heal: Restore an amount of your HP" << endl
			<< "Flee: Run away from battle" << endl << endl
			<< "-- Items --" << endl
			<< "Bombs: Deals 50HP to your opponent with no chance of missing" << endl
			<< "Arrows: Deals 10-15HP to your opponent with no chance of missing" << endl
			<< "Potion: Replenishes your HP to 100" << endl
			<< "Whetstone: Restores your weapon's sharpness." << endl << endl
			<< "Good luck and have fun!" << endl << endl
			<< "0) Quit" << endl << endl << "> ";
		break;
	default:
		break;
	}
}
<|endoftext|>