diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 692cb3c510..ed1dc38cec 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,27 @@ past entries belonging to author(s): Viktor Szakats. */ +2010-01-27 08:58 UTC-0800 Pritpal Bedi (pritpal@vouchcac.com) + * contrib/hbide/hbide.prg + * contrib/hbide/idemisc.prg + * contrib/hbide/ideprojmanager.prg + * contrib/hbide/resources/projectproperties.ui + + Implemented loading project from .hbp. + Look for the button on top of "Properties" dialog. + Please note that .hbp file is loaded with its whole + contentents and then is sectionized as per .hbi + protocol. So, the disadvantage is you loose the + free-format implementation of .hbp. It has to be + discovered how can we cover this aspect. Be careful + when building the project as existing .hbp will be + overwritten if you choose the "Project Location" + of the project pointing to same folder where .hbp + resides. Other than loosing "-skip" protocol of .hbp, + I am sure we are loosing nothing else, please test. + + + Implemention and options + which can be invoked from context menu of project node. + 2010-01-26 18:21 UTC-0800 Pritpal Bedi (pritpal@vouchcac.com) * contrib/hbide/idemisc.prg * contrib/hbide/ideprojmanager.prg diff --git a/harbour/contrib/hbide/hbide.prg b/harbour/contrib/hbide/hbide.prg index bf6f4e3628..3b01de8eab 100644 --- a/harbour/contrib/hbide/hbide.prg +++ b/harbour/contrib/hbide/hbide.prg @@ -216,7 +216,8 @@ CLASS HbIde METHOD setPosByIni( qWidget, nPart ) METHOD setSizeByIni( qWidget, nPart ) METHOD manageFocusInEditor() - METHOD updateProjectTree( aPrj, lRemove ) + METHOD removeProjectTree( aPrj ) + METHOD updateProjectTree( aPrj ) METHOD manageItemSelected( oXbpTreeItem ) METHOD manageProjectContext( mp1, mp2, oXbpTreeItem ) METHOD updateFuncList() @@ -331,7 +332,9 @@ METHOD HbIde:create( cProjIni ) ::cWrkProject := ::aINI[ INI_HBIDE, CurrentProject ] ::oPM:populate() ::oSM:loadSources() + #if 0 /* Must not be greyed as we have more options there */ ::updateProjectMenu() + #endif ::updateTitleBar() /* Set some last settings */ ::oPM:setCurrentProject( ::cWrkProject, .f. ) @@ -747,142 +750,110 @@ METHOD HbIde:manageFocusInEditor() /*----------------------------------------------------------------------*/ -METHOD HbIde:updateProjectTree( aPrj, lRemove ) - LOCAL cType, oParent, oP, aSrc, j, cProject, nPath - LOCAL aPath, aInUse, cPath, cFile, cExt, oPP, cPathA, nPos +METHOD HbIde:removeProjectTree( aPrj ) + LOCAL oProject, nIndex, oParent, oP, n - DEFAULT lRemove TO .F. - - IF Empty( aPrj ) + oProject := IdeProject():new( Self, aPrj ) + IF empty( oProject:title ) RETURN Self ENDIF - - cProject := aPrj[ PRJ_PRP_PROPERTIES, 2, E_oPrjTtl ] - - IF Empty( cProject ) - RETURN Self + nIndex := aScan( ::aProjData, {|e_| e_[ TRE_TYPE ] == "Project Name" .AND. e_[ TRE_ORIGINAL ] == oProject:title } ) + IF nIndex > 0 + oParent := ::aProjData[ nIndex, TRE_OITEM ] + DO WHILE .t. + n := ascan( ::aProjData, {|e_| e_[ TRE_OPARENT ] == oParent } ) + IF n == 0 + EXIT + ENDIF + oParent:delItem( ::aProjData[ n, TRE_OITEM ] ) + hb_adel( ::aProjData, n, .t. ) + ENDDO ENDIF - nPos := aScan( ::aProjData, {|e_| e_[ TRE_TYPE ] == "Project Name" .and. e_[ TRE_ORIGINAL ] == cProject } ) - cType := aPrj[ PRJ_PRP_PROPERTIES, 2, E_qPrjType ] + oP := oParent - DO CASE - CASE cType == "Executable" + SWITCH oProject:type + CASE "Executable" oParent := ::aProjData[ 1, 1 ] - CASE cType == "Lib" + EXIT + CASE "Lib" oParent := ::aProjData[ 2, 1 ] - CASE cType == "Dll" + EXIT + CASE "Dll" oParent := ::aProjData[ 3, 1 ] - ENDCASE + EXIT + ENDSWITCH - IF !( lRemove ) + nIndex := aScan( ::aProjData, {|e_| e_[ TRE_OITEM ] == oP } ) + oParent:delItem( oP ) + hb_adel( ::aProjData, nIndex, .t. ) - * It is a new node? - IF nPos == 0 - oParent:expand( .t. ) + RETURN Self - oP := oParent:addItem( cProject ) - aadd( ::aProjData, { oP, "Project Name", oParent, cProject, aPrj } ) - oParent := oP +/*----------------------------------------------------------------------*/ - * Need to be an update? - ELSE - nPos := aScan( oParent:aChilds, {|o| o:caption == cProject } ) +METHOD HbIde:updateProjectTree( aPrj ) + LOCAL oProject, n, oSource, oItem, nProjExists, oP, oParent, cPath - IF nPos <> 00 - oParent := oParent:aChilds[ nPos ] - ENDIF - ENDIF - - aSrc := aClone( aPrj[ PRJ_PRP_SOURCES, 2 ] ) - aSrc := ASort( aSrc ) - aPath := {} - aInUse:= {} - - * Load previous aPath used to fill ::aProjData - * 03/01/2010 - 16:08:25 - vailtom - FOR j := 1 TO LEN( ::aProjData ) - IF !hb_isChar( ::aProjData[ j, 5 ] ) .OR. ; // It is not a char? - ::aProjData[ j, TRE_TYPE ] != 'Path' .OR. ; // Is not an path? - ::aProjData[ j, TRE_DATA ] != cProject // Is not from same project? - LOOP - ENDIF - AAdd( aPath, { ::aProjData[ j, TRE_ORIGINAL ], ::aProjData[ j, 1 ]} ) - NEXT - - * Add new nodes with file names to tree... - FOR j := 1 TO len( aSrc ) - hb_fNameSplit( aSrc[ j ], @cPath, @cFile, @cExt ) - - cPathA := hbide_pathNormalized( cPath, .T. ) - nPath := aScan( aPath, {|e_| e_[ 1 ] == cPathA } ) - - AAdd( aInUse, cPathA ) - - * Find an node with Caption == cPathA - IF ( nPath == 0 ) - oPP := oParent:addItem( hbide_pathNormalized( cPath, .f. ) ) - aadd( ::aProjData, { oPP, "Path", oParent, cPathA, cProject } ) - aadd( aPath, { cPathA, oPP } ) - nPath := len( aPath ) - ENDIF - - oPP := aPath[ nPath,2 ] - cFile := cFile + cExt - nPos := aScan( ::aProjData, {|e_| e_[ TRE_TYPE ] == "Source File" .AND. ; - e_[ TRE_ORIGINAL ] == aSrc[ j ] } ) - IF nPos == 00 - aadd( ::aProjData, { oPP:addItem( cFile ), "Source File", oPP, aSrc[ j ], cProject } ) - ENDIF - NEXT - - * Remove deleted nodes from tree - FOR j := 1 TO LEN( ::aProjData ) - - * Is not from same project? - IF !hb_isChar( ::aProjData[ j, TRE_DATA ] ) .OR. ; - ::aProjData[ j, TRE_DATA ] != cProject - LOOP - ENDIF - - * It is a path? - IF ::aProjData[ j, 2 ] == 'Path' - cPathA := ::aProjData[ j, TRE_ORIGINAL ] - nPath := aScan( aInUse, {|e_| e_ == cPathA } ) - - IF nPath == 00 - ::aProjData[ j, TRE_OPARENT ]:delItem( ::aProjData[ j, 1 ] ) - hb_aDel( ::aProjData, j, .T. ) - ENDIF - - LOOP - ENDIF - - * It is a filename? - IF ::aProjData[ j, 2 ] == 'Source File' - cFile := ::aProjData[ j, TRE_ORIGINAL ] - nPos := aScan( aSrc, {|e_| e_ == cFile } ) - - IF nPos == 00 - ::aProjData[ j, TRE_OPARENT ]:delItem( ::aProjData[ j, TRE_OITEM ] ) - hb_aDel( ::aProjData, j, .T. ) - ENDIF - - LOOP - ENDIF - NEXT - - ELSE - - IF nPos != 0 - nPos := aScan( oParent:aChilds, {|e_| e_:Caption == cProject } ) - - IF nPos > 0 - oParent:delItem( oParent:aChilds[ nPos ] ) - ENDIF - ENDIF + oProject := IdeProject():new( Self, aPrj ) + IF empty( oProject:title ) + RETURN Self ENDIF + SWITCH oProject:type + CASE "Executable" + oParent := ::aProjData[ 1, 1 ] + EXIT + CASE "Lib" + oParent := ::aProjData[ 2, 1 ] + EXIT + CASE "Dll" + oParent := ::aProjData[ 3, 1 ] + EXIT + ENDSWITCH + + nProjExists := aScan( ::aProjData, {|e_| e_[ TRE_TYPE ] == "Project Name" .AND. e_[ TRE_ORIGINAL ] == oProject:title } ) + + IF nProjExists > 0 + nProjExists := aScan( oParent:aChilds, {|o| o:caption == oProject:title } ) + IF nProjExists > 0 + oP := oParent:aChilds[ nProjExists ] + ELSE + RETURN Self /* Some Error - It must never happen */ + ENDIF + /* Delete Existing Nodes */ + DO WHILE .t. + n := ascan( ::aProjData, {|e_| e_[ TRE_OPARENT ] == oP } ) + IF n == 0 + EXIT + ENDIF + oP:delItem( ::aProjData[ n, TRE_OITEM ] ) + hb_adel( ::aProjData, n, .t. ) + ENDDO + ENDIF + IF empty( oP ) + oParent:expand( .t. ) + oP := oParent:addItem( oProject:title ) + aadd( ::aProjData, { oP, "Project Name", oParent, oProject:title, aPrj, oProject } ) + ENDIF + oParent := oP + /* Reassign all children nodes */ + FOR EACH cPath IN oProject:hPaths + oItem := oParent:addItem( cPath:__enumKey() ) + aadd( ::aProjData, { oItem, "Path", oParent, cPath:__enumKey(), oProject:title, oProject } ) + NEXT + /* Souces */ + FOR EACH oSource IN oProject:hSources + n := ascan( ::aProjData, {|e_| e_[ TRE_TYPE ] == "Path" .AND. ; + e_[ TRE_ORIGINAL ] == oSource:path .AND. ; + e_[ TRE_DATA ] == oProject:title } ) + IF n > 0 + oP := ::aProjData[ n, TRE_OITEM ] + oItem := oP:addItem( oSource:file + oSource:ext ) + aadd( ::aProjData, { oItem, "Source File", oP, oSource:original, oProject:title } ) + ENDIF + NEXT + RETURN Self /*----------------------------------------------------------------------*/ @@ -953,7 +924,7 @@ METHOD HbIde:manageProjectContext( mp1, mp2, oXbpTreeItem ) IF !empty( ::oEV:getNames() ) aadd( aPops, { "" } ) FOR EACH s IN ::oEV:getNames() - aadd( aSub, { s , {|x| ::cWrkEnvironment := x, ::oDK:dispEnvironment( x ) } } ) + aadd( aSub, { s , {|x| ::cWrkEnvironment := x, ::oDK:dispEnvironment( x ) } } ) NEXT aadd( aPops, { aSub, "Environment..." } ) ENDIF @@ -978,11 +949,12 @@ METHOD HbIde:manageProjectContext( mp1, mp2, oXbpTreeItem ) aadd( aPops, { "" } ) aadd( aPops, { "Launch" , {|| ::oPM:launchProject( oXbpTreeItem:caption ) } } ) aadd( aPops, { "" } ) - aadd( aPops, { "Close This Project" , {|| ::oPM:closeProject( oXbpTreeItem:caption ) } } ) + aadd( aPops, { "Close this Project" , {|| ::oPM:closeProject( oXbpTreeItem:caption ) } } ) + aadd( aPops, { "Remove this Project" , {|| ::oPM:removeProject( oXbpTreeItem:caption ) } } ) IF !empty( ::oEV:getNames() ) aadd( aPops, { "" } ) FOR EACH s IN ::oEV:getNames() - aadd( aSub, { s , {|x| ::cWrkEnvironment := x, ::oDK:dispEnvironment( x ) } } ) + aadd( aSub, { s , {|x| ::cWrkEnvironment := x, ::oDK:dispEnvironment( x ) } } ) NEXT aadd( aPops, { aSub, "Select an environment" } ) ENDIF diff --git a/harbour/contrib/hbide/idemisc.prg b/harbour/contrib/hbide/idemisc.prg index 9c95b39e75..f748070538 100644 --- a/harbour/contrib/hbide/idemisc.prg +++ b/harbour/contrib/hbide/idemisc.prg @@ -1182,120 +1182,162 @@ FUNCTION hbide_getOS() RETURN cOS /*----------------------------------------------------------------------*/ -#if 0 -PROCEDURE hbide_convert_xhp_to_hbp( cSrcName ) - LOCAL cSrc := MemoRead( cSrcName ) - LOCAL cDst - LOCAL aDst := {} +/* + * Harbour Project source code: + * + * Copyright 2010 Viktor Szakats (harbour.01 syenar.hu) + * www - http://www.harbour-project.org + * + */ +#define HBIDE_HBP_PTYPE_FILES "files" +#define HBIDE_HBP_PTYPE_OPTIONS "options" +#define HBIDE_HBP_PTYPE_HBIDEPARAMS "hbideparams" + +FUNCTION hbide_fetchHbpData( cHBPFileName ) + LOCAL aParamList + + aParamList := hbide_HBPGetParamList( cHBPFileName ) + + hbide_dbg( "hbmk2 files" ) ; AEval( hbide_HBPParamListFilter( aParamList, HBIDE_HBP_PTYPE_FILES ), {| tmp | hbide_dbg( tmp ) } ) + hbide_dbg( "hbmk2 options" ) ; AEval( hbide_HBPParamListFilter( aParamList, HBIDE_HBP_PTYPE_OPTIONS ), {| tmp | hbide_dbg( tmp ) } ) + hbide_dbg( "hbide comments" ) ; AEval( hbide_HBPParamListFilter( aParamList, HBIDE_HBP_PTYPE_HBIDEPARAMS ), {| tmp | hbide_dbg( tmp ) } ) + + RETURN { hbide_HBPParamListFilter( aParamList, HBIDE_HBP_PTYPE_OPTIONS ), ; + hbide_HBPParamListFilter( aParamList, HBIDE_HBP_PTYPE_FILES ) } + +/*----------------------------------------------------------------------*/ + +FUNCTION hbide_HBPParamListFilter( aParams, nType ) + LOCAL aArray := {} LOCAL tmp - LOCAL cLine - LOCAL cSetting - LOCAL cValue - LOCAL aValue - LOCAL cFile - LOCAL hLIBPATH := {=>} - LOCAL cMAIN := NIL - LOCAL lFileSection := .F. + LOCAL cParamNQ - LOCAL cHome, cOutname, cType, cDefine, cInclude, aFiles := {} - LOCAL cRun, cParams, cDestntn, cMap - - - cSrc := StrTran( cSrc, Chr( 13 ) + Chr( 10 ), Chr( 10 ) ) - cSrc := StrTran( cSrc, Chr( 9 ), Chr( 32 ) ) - - FOR EACH cLine IN hb_ATokens( cSrc, Chr( 10 ) ) - IF cLine == "[Files]" - lFileSection := .T. - ELSEIF lFileSection - tmp := At( "=", cLine ) - IF tmp > 0 - cFile := AllTrim( Left( cLine, tmp - 1 ) ) - SWITCH Lower( FN_ExtGet( cFile ) ) - CASE ".c" - CASE ".prg" - IF !( "%HB_INSTALL%\" $ cFile ) - AAdd( aDst, StrTran( cFile, "%HOME%\" ) ) - ENDIF - EXIT - CASE ".lib" - CASE ".a" - IF !( "%C_LIB_INSTALL%\" $ cFile ) .AND. ; - !( "%HB_LIB_INSTALL%\" $ cFile ) - cFile := StrTran( cFile, "%HOME%\" ) - IF !( FN_DirGet( cFile ) $ hLIBPATH ) - hLIBPATH[ FN_DirGet( cFile ) ] := NIL - ENDIF - AAdd( aDst, "-l" + FN_NameGet( cFile ) ) - ENDIF - EXIT - CASE ".obj" - CASE ".o" - IF !( "%C_LIB_INSTALL%\" $ cFile ) .AND. ; - !( "%HB_LIB_INSTALL%\" $ cFile ) - AAdd( aDst, StrTran( cFile, "%HOME%\" ) ) - ENDIF - EXIT - ENDSWITCH + FOR EACH tmp IN aParams + DO CASE + CASE Lower( Left( tmp[ 1 ], 7 ) ) == "#hbide." + IF nType == HBIDE_HBP_PTYPE_HBIDEPARAMS + AAdd( aArray, tmp[ 1 ] ) ENDIF - ELSE - tmp := At( "=", cLine ) - IF tmp > 0 - cSetting := AllTrim( Left( cLine, tmp - 1 ) ) - cValue := AllTrim( SubStr( cLine, tmp + Len( "=" ) ) ) - aValue := hb_ATokens( cValue ) - IF ! Empty( cValue ) - SWITCH cSetting - CASE "Create Map/List File" - IF cValue == "Yes" - AAdd( aDst, "-map" ) - ENDIF - EXIT - CASE "Final Path" - IF ! Empty( cValue ) - AAdd( aDst, "-o" + DirAddPathSep( StrTran( cValue, "%HOME%\" ) ) ) - ENDIF - EXIT - CASE "Include" - FOR EACH tmp IN aValue - IF Left( tmp, 2 ) == "-I" - tmp := SubStr( tmp, 3 ) - ENDIF - AAdd( aDst, "-incpath=" + StrTran( StrTran( tmp, Chr( 34 ) ), "%HOME%\" ) ) - NEXT - EXIT - CASE "Define" - FOR EACH tmp IN aValue - IF Left( tmp, 2 ) == "-D" - tmp := SubStr( tmp, 3 ) - ENDIF - AAdd( aDst, "-D" + tmp ) - NEXT - EXIT - CASE "Params" - FOR EACH tmp IN aValue - AAdd( aDst, "-runflag=" + tmp ) - NEXT - EXIT - ENDSWITCH + CASE Left( tmp[ 1 ], 1 ) == "#" + /* misc comment line, always skip */ + CASE Empty( tmp[ 1 ] ) + /* empty line, always skip */ + OTHERWISE + cParamNQ := hbide_HBPStrStripQuote( tmp[ 1 ] ) + IF Left( cParamNQ, 1 ) == "-" + /* in conformance with hbmk2, skip remaining hbmk2 parameters if -skip is found */ + IF Lower( cParamNQ ) == "-skip" .AND. ( nType == HBIDE_HBP_PTYPE_FILES .OR. nType == HBIDE_HBP_PTYPE_OPTIONS ) + EXIT + ENDIF + IF nType == HBIDE_HBP_PTYPE_OPTIONS + AAdd( aArray, cParamNQ ) + ENDIF + ELSE + IF nType == HBIDE_HBP_PTYPE_FILES + AAdd( aArray, cParamNQ ) ENDIF ENDIF + ENDCASE + NEXT + + RETURN aArray + +/*----------------------------------------------------------------------*/ + +/* Load entire .hbp files, with empty lines and comments for + further processing. [vszakats] */ +FUNCTION hbide_HBPGetParamList( cFileName ) + LOCAL aParams := {} + + hbide_HBPLoad( aParams, cFileName ) + + RETURN aParams + +/*----------------------------------------------------------------------*/ + +/* Recursive .hbp/.hbm files are not currently supported. + It can be added, but it makes updating the options much more + complicated. [vszakats] */ + +#define HBIDE_HBP_EOL Chr( 10 ) + +STATIC PROCEDURE hbide_HBPLoad( aParams, cFileName ) + LOCAL cFile + LOCAL cLine + LOCAL cParam + LOCAl cParamNQ + + IF hb_FileExists( cFileName ) + + cFile := MemoRead( cFileName ) /* NOTE: Intentionally using MemoRead() which handles EOF char. */ + + IF ! hb_osNewLine() == HBIDE_HBP_EOL + cFile := StrTran( cFile, hb_osNewLine(), HBIDE_HBP_EOL ) + ENDIF + IF ! hb_osNewLine() == Chr( 13 ) + Chr( 10 ) + cFile := StrTran( cFile, Chr( 13 ) + Chr( 10 ), HBIDE_HBP_EOL ) ENDIF - NEXT - FOR EACH tmp IN hLIBPATH - AAdd( aDst, "-L" + tmp:__enumKey() ) - NEXT - - cDst := "" - FOR EACH tmp IN aDst - cDst += tmp + hb_osNewLine() - NEXT - - hbmk_OutStd( hb_StrFormat( I_( "Saving as .hbp file: %1$s" ), cDstName ) ) - - hb_MemoWrit( cDstName, cDst ) + FOR EACH cLine IN hb_ATokens( cFile, HBIDE_HBP_EOL ) + IF Empty( cLine ) .OR. ; + Left( cLine, 1 ) == "#" + AAdd( aParams, { cLine, cFileName, cLine:__enumIndex() } ) + ELSE + FOR EACH cParam IN hb_ATokens( cLine,, .T. ) + cParamNQ := hbide_HBPStrStripQuote( cParam ) + IF ! Empty( cParamNQ ) + DO CASE + CASE !( Left( cParamNQ, 1 ) == "-" ) .AND. Len( cParamNQ ) >= 1 .AND. Left( cParamNQ, 1 ) == "@" .AND. ; + !( Lower( hbide_HBPExtGet( cParamNQ ) ) == ".clp" ) + /* skip recurse */ + CASE !( Left( cParamNQ, 1 ) == "-" ) .AND. ; + ( Lower( hbide_HBPExtGet( cParamNQ ) ) == ".hbm" .OR. ; + Lower( hbide_HBPExtGet( cParamNQ ) ) == ".hbp" ) + /* skip recurse */ + OTHERWISE + AAdd( aParams, { cParam, cFileName, cLine:__enumIndex() } ) + ENDCASE + ENDIF + NEXT + ENDIF + NEXT + ENDIF RETURN -#endif + +/*----------------------------------------------------------------------*/ + +STATIC FUNCTION hbide_HBPStrStripQuote( cString ) + RETURN iif( Left( cString, 1 ) == '"' .AND. Right( cString, 1 ) == '"',; + SubStr( cString, 2, Len( cString ) - 2 ),; + cString ) + +/*----------------------------------------------------------------------*/ + +STATIC FUNCTION hbide_HBPExtGet( cFileName ) + LOCAL cExt + + hb_FNameSplit( cFileName,,, @cExt ) + + RETURN cExt + +/*----------------------------------------------------------------------*/ +// +/*----------------------------------------------------------------------*/ + +FUNCTION hbide_parseHbpFilter( s, cFilt, cPath ) + LOCAL n, n1 + + cFilt := "" + cPath := s + IF ( n := at( "{", s ) ) > 0 + IF ( n1 := at( "}", s ) ) > 0 + cFilt := substr( s, n + 1, n1 - n + 1 ) + cPath := alltrim( substr( s, n1 + 1 ) ) + RETURN .t. + ENDIF + ENDIF + + RETURN .f. + /*----------------------------------------------------------------------*/ diff --git a/harbour/contrib/hbide/ideprojmanager.prg b/harbour/contrib/hbide/ideprojmanager.prg index 10f23b04a2..5eda008c7f 100644 --- a/harbour/contrib/hbide/ideprojmanager.prg +++ b/harbour/contrib/hbide/ideprojmanager.prg @@ -77,15 +77,15 @@ CLASS IdeEnvironments - DATA oIde + DATA oIDE DATA cEnvFile DATA aNames INIT {} DATA aEnvrns INIT {} DATA aShellContents INIT {} DATA aCommons INIT {} - METHOD new( oIde, cEnvFile ) - METHOD create( oIde, cEnvFile ) + METHOD new( oIDE, cEnvFile ) + METHOD create( oIDE, cEnvFile ) METHOD parse( aContents ) METHOD prepareBatch( cEnviron ) METHOD getNames() INLINE ::aNames @@ -94,22 +94,22 @@ CLASS IdeEnvironments /*----------------------------------------------------------------------*/ -METHOD IdeEnvironments:new( oIde, cEnvFile ) +METHOD IdeEnvironments:new( oIDE, cEnvFile ) - ::oIde := oIde + ::oIDE := oIDE ::cEnvFile := cEnvFile RETURN Self /*----------------------------------------------------------------------*/ -METHOD IdeEnvironments:create( oIde, cEnvFile ) +METHOD IdeEnvironments:create( oIDE, cEnvFile ) LOCAL a_ - DEFAULT oIde TO ::oIde + DEFAULT oIDE TO ::oIDE DEFAULT cEnvFile TO ::cEnvFile - ::oIde := oIde + ::oIDE := oIDE ::cEnvFile := cEnvFile IF empty( ::cEnvFile ) .OR. !hb_fileExists( ::cEnvFile ) @@ -202,6 +202,42 @@ METHOD IdeEnvironments:prepareBatch( cEnviron ) RETURN cFile +/*----------------------------------------------------------------------*/ +// +// Class IdeSource +// +/*----------------------------------------------------------------------*/ + +CLASS IdeSource + + DATA original + DATA normalized + DATA filter + DATA path + DATA file + DATA ext + + METHOD new( cSource ) + + ENDCLASS + +/*----------------------------------------------------------------------*/ + +METHOD IdeSource:new( cSource ) + LOCAL cFilt, cPathFile, cPath, cFile, cExt + + hbide_parseHbpFilter( cSource, @cFilt, @cPathFile ) + hb_fNameSplit( cPathFile, @cPath, @cFile, @cExt ) + + ::original := cSource + ::normalized := hbide_pathNormalized( cSource, .t. ) + ::filter := cFilt + ::path := hbide_pathNormalized( cPath, .t. ) + ::file := cFile + ::ext := lower( cExt ) + + RETURN Self + /*----------------------------------------------------------------------*/ // // Class IdeProject @@ -231,8 +267,10 @@ CLASS IdeProject DATA compilers INIT "" DATA cPathMk2 INIT hb_getenv( "HBIDE_DIR_HBMK2" ) DATA cPathEnv INIT hb_DirBase() + "resources" + DATA hSources INIT {=>} + DATA hPaths INIT {=>} - METHOD new( oIde, aProps ) + METHOD new( oIDE, aProps ) METHOD applyMeta( s ) METHOD expandMeta( s ) @@ -240,17 +278,13 @@ CLASS IdeProject /*----------------------------------------------------------------------*/ -METHOD IdeProject:new( oIde, aProps ) - LOCAL b_, a_ +METHOD IdeProject:new( oIDE, aProps ) + LOCAL b_, a_, oSource, cSource IF hb_isArray( aProps ) .AND. !empty( aProps ) ::aProjProps := aProps b_:= aProps - - //::normalizedName := b_[ 1 ] - //::fileName := b_[ 2 ] - a_:= b_[ PRJ_PRP_PROPERTIES, 2 ] ::type := a_[ E_qPrjType ] @@ -274,16 +308,22 @@ METHOD IdeProject:new( oIde, aProps ) IF empty( ::wrkDirectory ) ::wrkDirectory := ::location ENDIF - IF !empty( oIde:aINI[ INI_HBIDE, PathMk2 ] ) - ::cPathMk2 := oIde:aINI[ INI_HBIDE, PathMk2 ] + IF !empty( oIDE:aINI[ INI_HBIDE, PathMk2 ] ) + ::cPathMk2 := oIDE:aINI[ INI_HBIDE, PathMk2 ] ENDIF - IF !empty( oIde:aINI[ INI_HBIDE, PathEnv ] ) - ::cPathEnv := oIde:aINI[ INI_HBIDE, PathEnv ] + IF !empty( oIDE:aINI[ INI_HBIDE, PathEnv ] ) + ::cPathEnv := oIDE:aINI[ INI_HBIDE, PathEnv ] ENDIF FOR EACH a_ IN ::metaData a_[ 2 ] := hbide_pathNormalized( a_[ 2 ], .f. ) NEXT + + FOR EACH cSource IN ::sources + oSource := IdeSource():new( cSource ) + ::hSources[ oSource:normalized ] := oSource + ::hPaths[ oSource:path ] := NIL + NEXT ENDIF RETURN Self @@ -334,9 +374,10 @@ CLASS IdeProjManager INHERIT IdeObject DATA oProject DATA cBatch DATA oProcess + DATA lSaveOK INIT .f. - METHOD new( oIde ) - METHOD create( oIde ) + METHOD new( oIDE ) + METHOD create( oIDE ) METHOD destroy() METHOD populate() @@ -353,8 +394,10 @@ CLASS IdeProjManager INHERIT IdeObject METHOD selectCurrentProject() METHOD getProjectProperties( cProjectTitle ) METHOD getProjectByFile( cProjectFile ) + METHOD getProjectFileNameFromTitle( cProjectTitle ) METHOD getProjectByTitle( cProjectTitle ) - METHOD closeProject( cProject ) + METHOD removeProject( cProjectTitle ) + METHOD closeProject( cProjectTitle ) METHOD promptForPath( cObjPathName, cTitle, cObjFileName, cObjPath2, cObjPath3 ) METHOD buildProject( cProject, lLaunch, lRebuild, lPPO, lViaQt ) METHOD launchProject( cProject ) @@ -363,23 +406,25 @@ CLASS IdeProjManager INHERIT IdeObject METHOD saveEnvironments() METHOD manageEnvironments() METHOD loadXhpProject() + METHOD loadHbpProject() + ENDCLASS /*----------------------------------------------------------------------*/ -METHOD IdeProjManager:new( oIde ) +METHOD IdeProjManager:new( oIDE ) - ::oIde := oIde + ::oIDE := oIDE RETURN Self /*----------------------------------------------------------------------*/ -METHOD IdeProjManager:create( oIde ) +METHOD IdeProjManager:create( oIDE ) - DEFAULT oIde TO ::oIde + DEFAULT oIDE TO ::oIDE - ::oIde := oIde + ::oIDE := oIDE RETURN Self @@ -457,12 +502,12 @@ METHOD IdeProjManager:loadProperties( cProjFileName, lNew, lFetch, lUpdateTree ) IF empty( ::aPrjProps ) ::aPrjProps := hbide_fetchHbiStructFromFile( hbide_pathToOSPath( cProjFileName ) ) ENDIF - ::oIde:aMeta := ::aPrjProps[ PRJ_PRP_METADATA, 2 ] + ::oIDE:aMeta := ::aPrjProps[ PRJ_PRP_METADATA, 2 ] ENDIF IF lFetch /* Access/Assign via this object */ - ::oProject := IdeProject():new( ::oIde, ::aPrjProps ) + ::oProject := IdeProject():new( ::oIDE, ::aPrjProps ) // ::fetchProperties() IF !empty( ::cSaveTo ) .and. hb_FileExists( ::cSaveTo ) @@ -471,16 +516,20 @@ METHOD IdeProjManager:loadProperties( cProjFileName, lNew, lFetch, lUpdateTree ) ENDIF ENDIF + IF lFetch .AND. empty( ::cSaveTo ) + RETURN Self + ENDIF + IF n == 0 - aadd( ::oIde:aProjects, { hbide_pathNormalized( cProjFileName ), cProjFileName, aclone( ::aPrjProps ) } ) + aadd( ::oIDE:aProjects, { hbide_pathNormalized( cProjFileName ), cProjFileName, aclone( ::aPrjProps ) } ) IF lUpdateTree - ::oIde:updateProjectTree( ::aPrjProps ) + ::oIDE:updateProjectTree( ::aPrjProps ) ENDIF - hbide_mnuAddFileToMRU( ::oIde, cProjFileName, INI_RECENTPROJECTS ) + hbide_mnuAddFileToMRU( ::oIDE, cProjFileName, INI_RECENTPROJECTS ) ELSE ::aProjects[ n, 3 ] := aclone( ::aPrjProps ) IF lUpdateTree - ::oIde:updateProjectTree( ::aPrjProps ) + ::oIDE:updateProjectTree( ::aPrjProps ) ENDIF IF lUpdateTree .AND. ::aPrjProps[ PRJ_PRP_PROPERTIES, 2, E_qPrjType ] <> t MsgBox( "::removeProjectFromTree( ::aPrjProps )" ) @@ -523,15 +572,17 @@ METHOD IdeProjManager:fetchProperties() ::oUI:q_buttonChooseDest :setIcon( cLukupPng ) ::oUI:q_buttonBackup :setIcon( cLukupPng ) ::oUI:q_buttonXmate :setIcon( ::resPath + "xmate.png" ) + ::oUI:q_buttonHbp :setIcon( ::resPath + "open.png" ) ::oUI:q_buttonSelect :setIcon( ::resPath + "open.png" ) ::oUI:q_buttonSort :setIcon( ::resPath + "toupper.png" ) // TODO: toupper.png => atoz.png ::oUI:q_buttonSortZA :setIcon( ::resPath + "tolower.png" ) // tolower.png => ztoa.png ::oUI:q_buttonSortOrg:setIcon( ::resPath + "invertcase.png" ) // tolower.png => ztoa.png - ::oUI:signal( "buttonCn" , "clicked()", {|| ::oUI:oWidget:close() } ) - ::oUI:signal( "buttonSave" , "clicked()", {|| ::save( .F. ) } ) - ::oUI:signal( "buttonSaveExit" , "clicked()", {|| ::save( .T. ) } ) + ::oUI:signal( "buttonCn" , "clicked()", {|| ::lSaveOK := .f., ::oUI:oWidget:close() } ) + ::oUI:signal( "buttonSave" , "clicked()", {|| ::lSaveOK := .t., ::save( .F. ) } ) + ::oUI:signal( "buttonSaveExit" , "clicked()", {|| ::lSaveOK := .t., ::save( .T. ) } ) + // ::oUI:signal( "buttonSelect" , "clicked()", {|| ::addSources() } ) ::oUI:signal( "buttonSort" , "clicked()", {|| ::sortSources( "az" ) } ) ::oUI:signal( "buttonSortZA" , "clicked()", {|| ::sortSources( "za" ) } ) @@ -545,6 +596,7 @@ METHOD IdeProjManager:fetchProperties() ::oUI:signal( "buttonChooseDest" , "clicked()", {|| ::PromptForPath( 'editDstFolder', 'Choose Destination Folder...' ) } ) ::oUI:signal( "buttonBackup" , "clicked()", {|| ::PromptForPath( 'editBackup' , 'Choose Backup Folder...' ) } ) ::oUI:signal( "buttonXmate" , "clicked()", {|| ::loadXhpProject() } ) + ::oUI:signal( "buttonHbp" , "clicked()", {|| ::loadHbpProject() } ) IF empty( ::aPrjProps ) /* @@ -688,6 +740,54 @@ METHOD IdeProjManager:save( lCanClose ) /*----------------------------------------------------------------------*/ +METHOD IdeProjManager:loadHbpProject() + LOCAL cHbp, aData, aOptns, aFiles, cHome, cOutName, cType, n + + cHbp := hbide_fetchAFile( ::oDlg, "Selecet Harbour Project File", { { "Harbour Project Files", "*.hbp" } } ) + IF empty( cHbp ) + RETURN Self + ENDIF + hb_fNameSplit( cHbp, @cHome, @cOutName ) + cHome := hbide_pathStripLastSlash( cHome ) + + aData := hbide_fetchHbpData( cHbp ) + aOptns := aData[ 1 ] + aFiles := aData[ 2 ] + + IF ( n := ascan( aOptns, {|e| lower( e ) $ "-hbexec,-hblib,-hbdyn" } ) ) > 0 + cType := lower( aOptns[ n ] ) + ELSE + cType := "" + ENDIF + /* Basic Parsing is complete , parse paths from keywords */ + SWITCH cType + CASE "-hblib" + ::oUI:q_comboPrjType:setCurrentIndex( 1 ) + EXIT + CASE "-hbdyn" + ::oUI:q_comboPrjType:setCurrentIndex( 2 ) + EXIT + OTHERWISE + ::oUI:q_comboPrjType:setCurrentIndex( 0 ) + EXIT + ENDSWITCH + + ::oUI:q_editPrjTitle :setText( cOutName ) + ::oUI:q_editPrjLoctn :setText( cHome ) +* ::oUI:q_editWrkFolder:setText( "" ) + ::oUI:q_editDstFolder:setText( "" ) /* To parse -o : but first fix path verification to honor filters */ +* ::oUI:q_editBackup :setText( "" ) + ::oUI:q_editOutName :setText( cOutName ) +* ::oUI:q_editLaunchParams:setText( cParams ) +* ::oUI:q_editLaunchExe:setText( cRun ) + + ::oUI:q_editFlags :setPlainText( hbide_arrayToMemo( aOptns ) ) + ::oUI:q_editSources:setPlainText( hbide_arrayToMemo( aFiles ) ) + + RETURN Self + +/*----------------------------------------------------------------------*/ + METHOD IdeProjManager:loadXhpProject() LOCAL cXhp, a_, s, n, cPart, cKey, cVal LOCAL cHome, cOutname, cType, cDefine, cInclude @@ -909,11 +1009,11 @@ METHOD IdeProjManager:saveEnvironments() cPathMk2 := ::oUI:q_editPathMk2:text() cPathEnv := ::oUI:q_editPathEnv:text() - ::oIde:aINI[ INI_HBIDE, PathMk2 ] := cPathMk2 - ::oIde:aINI[ INI_HBIDE, PathEnv ] := cPathEnv + ::oIDE:aINI[ INI_HBIDE, PathMk2 ] := cPathMk2 + ::oIDE:aINI[ INI_HBIDE, PathEnv ] := cPathEnv // - ::oIde:cWrkPathMk2 := cPathMk2 - ::oIde:cWrkPathEnv := cPathEnv + ::oIDE:cWrkPathMk2 := cPathMk2 + ::oIDE:cWrkPathEnv := cPathEnv IF !empty( cText := ::oUI:q_editCompilers:toPlainText() ) hb_MemoWrit( hbide_pathFile( cPathEnv, "hbide.env" ), cText ) @@ -1083,11 +1183,11 @@ METHOD IdeProjManager:setCurrentProject( cProjectName ) LOCAL lValid := .T. IF Empty( cProjectName ) - ::oIde:cWrkProject := '' + ::oIDE:cWrkProject := '' ELSEIF ( n := ascan( ::aProjects, {|e_| e_[ 3, PRJ_PRP_PROPERTIES, 2, E_oPrjTtl ] == cProjectName } ) ) > 0 aPrjProps := ::aProjects[ n, 3 ] - ::oIde:cWrkProject := aPrjProps[ PRJ_PRP_PROPERTIES, 2, E_oPrjTtl ] + ::oIDE:cWrkProject := aPrjProps[ PRJ_PRP_PROPERTIES, 2, E_oPrjTtl ] ELSE * MsgBox( 'Invalid project selected: "' + cProjectName + '"' ) @@ -1100,22 +1200,24 @@ METHOD IdeProjManager:setCurrentProject( cProjectName ) ::oSBar:getItem( SB_PNL_PROJECT ):caption := ::cWrkProject ENDIF - ::oIde:updateTitleBar() - ::oIde:updateProjectMenu() + ::oIDE:updateTitleBar() + #if 0 /* It must not be as there are more actions attached */ + ::oIDE:updateProjectMenu() + #endif /* Reset Old Color */ IF !empty( cOldProject ) - IF !empty( oItem := hbide_findProjTreeItem( ::oIde, cOldProject, "Project Name" ) ) + IF !empty( oItem := hbide_findProjTreeItem( ::oIDE, cOldProject, "Project Name" ) ) oItem:oWidget:setForeground( 0, QBrush():new( "QColor", QColor():new( 0,0,0 ) ) ) //oItem:oWidget:setBackground( 0, QBrush():new( "QColor", QColor():new( 255,255,255 ) ) ) ENDIF ENDIF /* Set New Color */ IF !empty( ::cWrkProject ) - IF !empty( oItem := hbide_findProjTreeItem( ::oIde, ::cWrkProject, "Project Name" ) ) + IF !empty( oItem := hbide_findProjTreeItem( ::oIDE, ::cWrkProject, "Project Name" ) ) oItem:oWidget:setForeground( 0, ::qBrushWrkProject ) //oItem:oWidget:setBackground( 0, ::qBrushWrkProject ) - hbide_expandChildren( ::oIde, oItem ) + hbide_expandChildren( ::oIDE, oItem ) ::oProjTree:oWidget:setCurrentItem( oItem:oWidget ) ENDIF ENDIF @@ -1158,7 +1260,7 @@ METHOD IdeProjManager:selectCurrentProject() ENDIF oDlg := HbpQtUI():new( ::oDlg ) - oDlg:file := ::oIde:resPath + "selectproject.ui" + oDlg:file := ::oIDE:resPath + "selectproject.ui" oDlg:create() * Fill ComboBox with current project names @@ -1203,7 +1305,18 @@ METHOD IdeProjManager:getProjectByFile( cProjectFile ) aProj := ::aProjects[ n ] ENDIF - RETURN IdeProject():new( ::oIde, aProj ) + RETURN IdeProject():new( ::oIDE, aProj ) + +/*----------------------------------------------------------------------*/ + +METHOD IdeProjManager:getProjectFileNameFromTitle( cProjectTitle ) + LOCAL n, cProjFileName := "" + + IF ( n := ascan( ::aProjects, {|e_, x| x := e_[ 3 ], x[ 1, 2, PRJ_PRP_TITLE ] == cProjectTitle } ) ) > 0 + cProjFileName := ::aProjects[ n, 2 ] + ENDIF + + RETURN cProjFileName /*----------------------------------------------------------------------*/ @@ -1214,29 +1327,42 @@ METHOD IdeProjManager:getProjectByTitle( cProjectTitle ) aProj := ::aProjects[ n, 3 ] ENDIF - RETURN IdeProject():new( ::oIde, aProj ) + RETURN IdeProject():new( ::oIDE, aProj ) /*----------------------------------------------------------------------*/ -METHOD IdeProjManager:closeProject( cProject ) - LOCAL nPos +METHOD IdeProjManager:removeProject( cProjectTitle ) + LOCAL cProjFileName, nPos + + IF !empty( cProjFileName := ::getProjectFileNameFromTitle( cProjectTitle ) ) + ::closeProject( cProjectTitle ) + + nPos := ascan( ::aProjects, {|e_| e_[ 2 ] == cProjFileName } ) + IF nPos > 0 + hb_adel( ::aProjects, nPos, .T. ) + hbide_saveINI( ::oIDE ) + ENDIF + ENDIF + + RETURN Self + +/*----------------------------------------------------------------------*/ + +METHOD IdeProjManager:closeProject( cProjectTitle ) + LOCAL oProject, aProp IF Empty( ::aProjects ) - MsgBox( "No Projects Available" ) RETURN Self ENDIF - DEFAULT cProject TO ::getCurrentProject() - - nPos := ascan( ::aProjects, {|e_| e_[ 3, PRJ_PRP_PROPERTIES, 2, E_oPrjTtl ] == cProject } ) - IF ( nPos < 0 ) - MsgBox( 'Invalid project: "' + cProject + '"' ) + aProp := ::getProjectProperties( cProjectTitle ) + oProject := IdeProject():new( ::oIDE, aProp ) + IF empty( oProject:title ) RETURN Self ENDIF - ::aPrjProps := {} - ::updateProjectTree( ::aProjects[ nPos, 3 ], .T. ) - hb_adel( ::aProjects, nPos, .T. ) + ::oIDE:removeProjectTree( aProp ) + ::setCurrentProject( '' ) RETURN Self @@ -1384,7 +1510,7 @@ METHOD IdeProjManager:buildProject( cProject, lLaunch, lRebuild, lPPO, lViaQt ) ENDIF ENDIF - ::oIde:lDockBVisible := .t. + ::oIDE:lDockBVisible := .t. ::oDockB2:show() ::oOutputResult:oWidget:clear() @@ -1400,7 +1526,7 @@ METHOD IdeProjManager:buildProject( cProject, lLaunch, lRebuild, lPPO, lViaQt ) hbide_outputLine() + CRLF ::oOutputResult:oWidget:append( cTmp ) - ::oIde:oEV := IdeEnvironments():new():create( ::oIde, hbide_pathFile( ::aINI[ INI_HBIDE, PathEnv ], "hbide.env" ) ) + ::oIDE:oEV := IdeEnvironments():new():create( ::oIDE, hbide_pathFile( ::aINI[ INI_HBIDE, PathEnv ], "hbide.env" ) ) ::cBatch := ::oEV:prepareBatch( ::cWrkEnvironment ) #if 0 /* This does not works - reason being it picks up hbmk2 from fixed location */ cExeHbMk2 := hbide_pathFile( ::oProject:cPathMk2, "hbmk2" ) @@ -1469,8 +1595,7 @@ METHOD IdeProjManager:finished( nExitCode, nExitStatus, oProcess ) * 03/01/2010 - 09:24:50 */ METHOD IdeProjManager:launchProject( cProject ) - LOCAL cTargetFN, cTmp, oProject - LOCAL qProcess + LOCAL cTargetFN, cTmp, oProject, qProcess IF empty( cProject ) cProject := ::oPM:getCurrentProject() diff --git a/harbour/contrib/hbide/resources/projectproperties.ui b/harbour/contrib/hbide/resources/projectproperties.ui index 3aa9b42d55..eeb33fb2b5 100644 --- a/harbour/contrib/hbide/resources/projectproperties.ui +++ b/harbour/contrib/hbide/resources/projectproperties.ui @@ -73,7 +73,7 @@ p, li { white-space: pre-wrap; } - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> @@ -263,10 +263,34 @@ p, li { white-space: pre-wrap; } - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Loading a .hbp project file is essentially a </p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">task of redefining its flow and contents order.</p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hbIDE rewrites the existing .hbp file if the </p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">"Project Location" points to same folder </p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">where your such loaded .hbp resides.</p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">So</p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">take care to change the "Project Location"</span></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to different folder than home folder of .hbp.</p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is done at the time of "Build" process.</p></body></html> + + + ... + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> @@ -275,11 +299,26 @@ p, li { white-space: pre-wrap; } <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hbIDE attempts to recognize various components</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">but it is possible that it may not load everything.</p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">So you may need manual editing.</p></body></html> - - - ... - - + + + ... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + +