# # # rename "bin" # to "guitone/bin" # # rename "res" # to "guitone/res" # # rename "src" # to "guitone/src" # # add_dir "guitone" # # add_dir "libs" # # add_dir "libs/qanava" # # add_dir "libs/qanava/build" # # add_dir "libs/qanava/build/pro" # # add_dir "libs/qanava/build/pro/can" # # add_dir "libs/qanava/build/pro/la" # # add_dir "libs/qanava/build/pro/ui" # # add_dir "libs/qanava/build/pro/utl" # # add_dir "libs/qanava/build/vc71" # # add_dir "libs/qanava/src" # # add_dir "libs/qanava/src/can" # # add_dir "libs/qanava/src/la" # # add_dir "libs/qanava/src/ui" # # add_dir "libs/qanava/src/utl" # # add_file "guitone/guitone.pro" # content [dd29e1ed22d90e4a108e51568b340b53847921ea] # # add_file "libs/libs.pro" # content [ca5044adbf8828221942c937a63e7b40638b4aea] # # add_file "libs/qanava/build/build.pro" # content [d353f2eb900069df488d68e1d2ed4bedd83786dd] # # add_file "libs/qanava/build/pro/can/can.pro" # content [c2924c9143f7155212e9ef11009aa25f3c912480] # # add_file "libs/qanava/build/pro/can/can.vcproj" # content [9e4654b0a6b68238249dff41e03b3978659fc180] # # add_file "libs/qanava/build/pro/la/la.pro" # content [9d44eeabbad45073a0c5998cf87f539fb48e2141] # # add_file "libs/qanava/build/pro/la/la.vcproj" # content [92e35d62e6ac9073897560549f65e71fe176dc58] # # add_file "libs/qanava/build/pro/pro.pro" # content [21029d62e0f9bebd93a6d69af22b390b0a8ff8b1] # # add_file "libs/qanava/build/pro/ui/ui.pro" # content [f982a39b1b02c1a88f8c55f35f15bc4bf4339b48] # # add_file "libs/qanava/build/pro/ui/ui.vcproj" # content [27556f6c5e8220426de2981781da91d437c0d70a] # # add_file "libs/qanava/build/pro/utl/utl.pro" # content [c4512de66632bff5f9e08c402321a20d9787b60e] # # add_file "libs/qanava/build/pro/utl/utl.vcproj" # content [850872df193be444b7c0957cabff2482643c7753] # # add_file "libs/qanava/build/vc71/qanava.sln" # content [f0baa870483482865bc22f324064e1213adcedee] # # add_file "libs/qanava/licence.txt" # content [caeb68c46fa36651acf592771d09de7937926bb3] # # add_file "libs/qanava/qanava.pro" # content [724ad04ac46172941865f341becdbd98a4d362d8] # # add_file "libs/qanava/readme.txt" # content [57df6d534b3a5cdd1bbcae44047f0ba67377f170] # # add_file "libs/qanava/src/can/canController.cpp" # content [3e27498d50aa0b884f20990971fd2d96dbab9c76] # # add_file "libs/qanava/src/can/canController.h" # content [8bf4163cd12f695e4aaf5c96559f9b9b8cefd1b2] # # add_file "libs/qanava/src/can/canGraphItemModel.cpp" # content [1574e9b6984daf1de4e9b9168e8517dafc794b39] # # add_file "libs/qanava/src/can/canGraphItemModel.h" # content [7488f5eddb6f46176ec2a43e281682acbd707f7e] # # add_file "libs/qanava/src/can/canGraphItemView.cpp" # content [9f7d36b2ea896d61870bb1564cf3b3a52debb32f] # # add_file "libs/qanava/src/can/canGraphItemView.h" # content [978a8a7cfb5c35da58ec0f0a4b9b9b686809b7e9] # # add_file "libs/qanava/src/can/canGraphicsView.cpp" # content [7939221fdb922f5b8cd345081892f970cce3a331] # # add_file "libs/qanava/src/can/canGraphicsView.h" # content [d507ca7454e22edc14aa0ad3bfccb5721110b9c1] # # add_file "libs/qanava/src/can/canGrid.cpp" # content [2e8ad9f3cd734e63856b1c8a7ff8675ae42d5eec] # # add_file "libs/qanava/src/can/canGrid.h" # content [4644ad4dfd030e2e00d101f7c5ed425c51a2c25e] # # add_file "libs/qanava/src/can/canItemGeom.cpp" # content [a7fd96e347cf762c95252ab333a1fad3947f5599] # # add_file "libs/qanava/src/can/canItemGeom.h" # content [d086d24b922634654241adc27d2126f0ab21b6fa] # # add_file "libs/qanava/src/can/canProgressQt.cpp" # content [30308ac7406f7e64d4f9197f8f65348be02412f3] # # add_file "libs/qanava/src/can/canProgressQt.h" # content [2bee97ad4bf1c502676b59207f15b8d9f1df8cc0] # # add_file "libs/qanava/src/can/canStyle.cpp" # content [379896dd7657c78e88344dd2ff441f910b512654] # # add_file "libs/qanava/src/can/canStyle.h" # content [d07d8392e66b0864ba11ed0361491579dd3abadc] # # add_file "libs/qanava/src/la/laEdge.cpp" # content [6a89d9b6c76605086f5803912f46f4b8119f2bf3] # # add_file "libs/qanava/src/la/laEdge.h" # content [8ffb7a16203557dd5c09ed82f70df480021973f5] # # add_file "libs/qanava/src/la/laGraph.cpp" # content [be2e22c1a71c3c0b8716b2da649942e78e56f48b] # # add_file "libs/qanava/src/la/laGraph.h" # content [e25200416eafafdee8d09d801f1268bf67eb334d] # # add_file "libs/qanava/src/la/laGrid.cpp" # content [5e32dd40c64db52ff4db4735ef58dc489ec18bd5] # # add_file "libs/qanava/src/la/laGrid.h" # content [b22d655feab86d7cab3e4581fd87b3efcffe573f] # # add_file "libs/qanava/src/la/laLayout.cpp" # content [952b2d3a34c69bee229fb8ea0ab77ecab1154eac] # # add_file "libs/qanava/src/la/laLayout.h" # content [28ef82ee266b4918b0a5cc146c6f8528dc8ee26f] # # add_file "libs/qanava/src/la/laNode.cpp" # content [41129452cf3dcd33b503e2c0a3af5d81abc40366] # # add_file "libs/qanava/src/la/laNode.h" # content [39795c963f6c9fa5a1bd71fa80818d1eaed2ec23] # # add_file "libs/qanava/src/la/laRepository.cpp" # content [0aee16d368abe8b5066d29f4b73bb990ac548f42] # # add_file "libs/qanava/src/la/laRepository.h" # content [d8dc9c74947562f09270d3d56fb3929bc1bc7027] # # add_file "libs/qanava/src/la/laTimeTree.cpp" # content [f1c5adc6b822976aaf94269507841747570d8b96] # # add_file "libs/qanava/src/la/laTimeTree.h" # content [1c33e3eef71fccd26284041f71be2b57d58034af] # # add_file "libs/qanava/src/la/laVectorF.h" # content [b3718c42e0657dc330ffc9dab4fbbee849bff0be] # # add_file "libs/qanava/src/ui/uiItemListView.ui" # content [ad5879ef3b618c0553e56caeb7da103be279c7aa] # # add_file "libs/qanava/src/ui/uiNodesItemModel.cpp" # content [8a2726a355ef1618de42a2e25c35660cf4eb2fc2] # # add_file "libs/qanava/src/ui/uiNodesItemModel.h" # content [9602a8cb289244281dba46cbae59153ba5720234] # # add_file "libs/qanava/src/ui/uiStyleModel.cpp" # content [9027a6909c05fbe08532f4430bad71468e6b515e] # # add_file "libs/qanava/src/ui/uiStyleModel.h" # content [8646ef850e3bd7efb64c147018f6f65aa0e6c76d] # # add_file "libs/qanava/src/ui/uiStyleView.cpp" # content [e357ecea2bab03cbc6e958a8168219615c6dc536] # # add_file "libs/qanava/src/ui/uiStyleView.h" # content [33c1b960b744e41f1b9fd1bbff5f046df28ab91e] # # add_file "libs/qanava/src/ui/uiStyleView.ui" # content [3415d8ca187cfc1de191578b704cdd0d20fda3ff] # # add_file "libs/qanava/src/ui/uiUtil.h" # content [358bed6be6af36e35187e4d18a2ac8e29f8d5fb4] # # add_file "libs/qanava/src/utl/utlConfig.h" # content [e45de8e04055ac0b668eccc0eb2281dd8f2d591b] # # add_file "libs/qanava/src/utl/utlManager.h" # content [b17e0d2c98e6b0181518b29c47a000c162a62ce3] # # add_file "libs/qanava/src/utl/utlManager.hpp" # content [7cb1fd07f16f0e6bda399805c7b79779aff739fd] # # add_file "libs/qanava/src/utl/utlProgress.cpp" # content [03f6517f44e4b70b18e365216395b5367ae27e30] # # add_file "libs/qanava/src/utl/utlProgress.h" # content [2c595ced20ea2b3c0e8d9358e89583d88fa9f3ab] # # patch ".mtn-ignore" # from [d12ed1ba7c0f020192430ea692ad88d953b74cb0] # to [73f2fd80083fdbd3aa6c139bbefd78727f2cffb2] # # patch "README" # from [3becea4a889f548a17cdfb9c9f504d181b5d9834] # to [42ca1d930985fcd7e53b87f05e1774ad41213e0f] # # patch "build.sh" # from [34a577b8e06c930c6508418e3036426b7210d6f1] # to [f2e5495f9013a8b24e8dfecffea3015ea68f86d1] # # patch "guitone/res/i18n/guitone_de.ts" # from [3b0993a128ae9a40dbf4ace8009c6c82adc0c349] # to [9857927823e1d6a0339b531c120dcaadd22d25e9] # # patch "guitone/src/model/InventoryProxyModel.cpp" # from [6c7a00ab4949ebcc9d919e053722e2db6679b0a6] # to [e87bd50fd656e93a576f1d6786188ae5ab3da20d] # # patch "guitone/src/util/IconProvider.cpp" # from [0dd668940db7738994731e99d18a45b201e4564f] # to [373b291301e12a327932f1280dafe27da638e7b6] # # patch "guitone/src/view/AttributesView.cpp" # from [7c594a67cea2d436ad1359d518a4ef5b5bfa7c7c] # to [f248dcfc64ac35f606b7e8da3f7b6f02fcadb857] # # patch "guitone/src/view/Splitter.cpp" # from [bb5050294e328b9a74cd3d58faeac27094cf3c2d] # to [e339e7a165c79c7d57d4e469c8c003eb6c7c8c7f] # # patch "guitone/src/view/TreeView.cpp" # from [3fed528b1ae9f72cfe90380641e9a9f96872f212] # to [cc5a064468706cc94cf3e1a8a2695c07beb2819b] # # patch "guitone/src/view/dialogs/ui_KeyManagment.h" # from [e82e9ba78fec73e56da2e9b08b2d64171849f85d] # to [ef076eb7a2ef3e3d88e008a296fdd25eed8400b7] # # patch "guitone/src/view/dialogs/ui_preferences.h" # from [7bf70ad1a88dcebe0fc90dc4eb0a309463676980] # to [241e018833bdf465c7cce8a41e7c3a0980d1fcb1] # # patch "guitone/src/view/dialogs/ui_switch_workspace.h" # from [9ea0d34e428e64e6f73521babeb3be52b12becd1] # to [7f800f9ff1683e12662b86fc5a9ad5188368b4a0] # # patch "guitone.pro" # from [0c104884af75f7cd2bfc2e950dc56885da79301e] # to [d25442e228ae59d846371735ed708838c8d3bcf9] # ============================================================ --- guitone/guitone.pro dd29e1ed22d90e4a108e51568b340b53847921ea +++ guitone/guitone.pro dd29e1ed22d90e4a108e51568b340b53847921ea @@ -0,0 +1,73 @@ +TEMPLATE = app +TARGET = guitone +CONFIG += qt debug precompile_header +HEADERS += src/view/Guitone.h \ + src/view/TreeView.h \ + src/view/Splitter.h \ + src/view/InventoryView.h \ + src/view/AttributesView.h \ + src/view/dialogs/SwitchWorkspaceRevision.h \ + src/view/dialogs/Preferences.h \ + src/view/dialogs/KeyManagment.h \ + src/monotone/Monotone.h \ + src/model/AutomateCommand.h \ + src/model/Inventory.h \ + src/model/InventoryItem.h \ + src/model/InventoryProxyModel.h \ + src/model/Attributes.h \ + src/model/Select.h \ + src/model/Certs.h \ + src/util/IconProvider.h \ + src/util/StanzaParser.h \ + src/util/Settings.h +SOURCES += src/view/Guitone.cpp \ + src/view/TreeView.cpp \ + src/view/Splitter.cpp \ + src/view/InventoryView.cpp \ + src/view/AttributesView.cpp \ + src/view/dialogs/SwitchWorkspaceRevision.cpp \ + src/view/dialogs/Preferences.cpp \ + src/view/dialogs/KeyManagment.cpp \ + src/monotone/Monotone.cpp \ + src/model/AutomateCommand.cpp \ + src/model/Inventory.cpp \ + src/model/InventoryItem.cpp \ + src/model/InventoryProxyModel.cpp \ + src/model/Attributes.cpp \ + src/model/Select.cpp \ + src/model/Certs.cpp \ + src/util/IconProvider.cpp \ + src/util/StanzaParser.cpp \ + src/util/Settings.cpp \ + src/main.cpp +FORMS += res/dialogs/switch_workspace.ui \ + res/dialogs/preferences.ui \ + res/dialogs/KeyManagment.ui +UI_DIR = src/view/dialogs +OBJECTS_DIR = tmp +MOC_DIR = tmp +DESTDIR = bin +TRANSLATIONS = res/i18n/guitone_de.ts +RESOURCES = res/guitone.qrc +RCC_DIR = tmp +PRECOMPILED_HEADER = src/stable.h + +macx { + # copy i18n resources into the final app bundle + QMAKE_POST_LINK = cp -R res/osx/Resources bin/guitone.app/Contents + + # osx application icon + ICON = res/osx/guitone.icns + + # set this to either ppc or i386 or both if you want to create + # a PowerPC, x86 or Universal OSX binary + debug { + CONFIG += ppc + } + release { + CONFIG += ppc + } + # path to the OSX universal SDK + QMAKE_MAC_SDK = /Developer/SDKs/MacOSX10.4u.sdk +} + ============================================================ --- libs/libs.pro ca5044adbf8828221942c937a63e7b40638b4aea +++ libs/libs.pro ca5044adbf8828221942c937a63e7b40638b4aea @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = qanava + ============================================================ --- libs/qanava/build/build.pro d353f2eb900069df488d68e1d2ed4bedd83786dd +++ libs/qanava/build/build.pro d353f2eb900069df488d68e1d2ed4bedd83786dd @@ -0,0 +1,2 @@ +TEMPLATE=subdirs +SUBDIRS=pro ============================================================ --- libs/qanava/build/pro/can/can.pro c2924c9143f7155212e9ef11009aa25f3c912480 +++ libs/qanava/build/pro/can/can.pro c2924c9143f7155212e9ef11009aa25f3c912480 @@ -0,0 +1,41 @@ + +LANGUAGE = C++ +DEFINES = QANAVA +TARGET = qanava_can +DESTDIR = ../../ +CONFIG += debug \ + warn_on \ + qt \ + thread staticlib +TEMPLATE = lib +HEADERS += ../../../src/can/canController.h \ + ../../../src/can/canItemGeom.h \ + ../../../src/can/canStyle.h \ + ../../../src/can/canGraphicsView.h \ + ../../../src/can/canGraphItemView.h \ + ../../../src/can/canGraphItemModel.h \ + ../../../src/can/canGrid.h \ + ../../../src/can/canProgressQt.h + +SOURCES += ../../../src/can/canController.cpp \ + ../../../src/can/canItemGeom.cpp \ + ../../../src/can/canStyle.cpp \ + ../../../src/can/canGraphicsView.cpp \ + ../../../src/can/canGraphItemView.cpp \ + ../../../src/can/canGraphItemModel.cpp \ + ../../../src/can/canGrid.cpp \ + ../../../src/can/canProgressQt.cpp +unix{ + QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter + TEMPLATE = lib + UI_DIR = .ui + MOC_DIR = .moc + OBJECTS_DIR = .obj + DEFINES += QANAVA_LINUX +} +win32{ + TEMPLATE = vclib + QMAKE_MAKEFILE = can.vcproj + OBJECTS_DIR = ./Debug +} + ============================================================ --- libs/qanava/build/pro/can/can.vcproj 9e4654b0a6b68238249dff41e03b3978659fc180 +++ libs/qanava/build/pro/can/can.vcproj 9e4654b0a6b68238249dff41e03b3978659fc180 @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ============================================================ --- libs/qanava/build/pro/la/la.pro 9d44eeabbad45073a0c5998cf87f539fb48e2141 +++ libs/qanava/build/pro/la/la.pro 9d44eeabbad45073a0c5998cf87f539fb48e2141 @@ -0,0 +1,39 @@ + +LANGUAGE = C++ +DEFINES = QANAVA +TARGET = qanava_la +DESTDIR = ../../ +CONFIG += debug \ + warn_on \ + qt \ + thread staticlib +QT += xml +TEMPLATE = lib +HEADERS += ../../../src/la/laEdge.h \ + ../../../src/la/laGraph.h \ + ../../../src/la/laGrid.h \ + ../../../src/la/laLayout.h \ + ../../../src/la/laNode.h \ + ../../../src/la/laVectorf.h \ + ../../../src/la/laRepository.h \ + ../../../src/la/laTimeTree.h +SOURCES += ../../../src/la/laEdge.cpp \ + ../../../src/la/laGraph.cpp \ + ../../../src/la/laGrid.cpp \ + ../../../src/la/laLayout.cpp \ + ../../../src/la/laNode.cpp \ + ../../../src/la/laRepository.cpp \ + ../../../src/la/laTimeTree.cpp +unix{ + QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter + TEMPLATE = lib + UI_DIR = .ui + MOC_DIR = .moc + OBJECTS_DIR = .obj + DEFINES += QANAVA_LINUX +} +win32{ + TEMPLATE = vclib + QMAKE_MAKEFILE = la.vcproj + OBJECTS_DIR = ./Debug +} ============================================================ --- libs/qanava/build/pro/la/la.vcproj 92e35d62e6ac9073897560549f65e71fe176dc58 +++ libs/qanava/build/pro/la/la.vcproj 92e35d62e6ac9073897560549f65e71fe176dc58 @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ============================================================ --- libs/qanava/build/pro/pro.pro 21029d62e0f9bebd93a6d69af22b390b0a8ff8b1 +++ libs/qanava/build/pro/pro.pro 21029d62e0f9bebd93a6d69af22b390b0a8ff8b1 @@ -0,0 +1,2 @@ +TEMPLATE=subdirs +SUBDIRS=can la utl ui ============================================================ --- libs/qanava/build/pro/ui/ui.pro f982a39b1b02c1a88f8c55f35f15bc4bf4339b48 +++ libs/qanava/build/pro/ui/ui.pro f982a39b1b02c1a88f8c55f35f15bc4bf4339b48 @@ -0,0 +1,35 @@ + +LANGUAGE = C++ +DEFINES = QANAVA +TARGET = qanava_ui +DESTDIR = ../../ +CONFIG += debug \ + warn_on \ + qt \ + thread staticlib + +TEMPLATE = lib +HEADERS += ../../../src/ui/uiStyleView.h \ + ../../../src/ui/uiStyleModel.h \ + ../../../src/ui/uiNodesItemModel.h \ + ../../../src/ui/uiUtil.h + + +SOURCES += ../../../src/ui/uiStyleView.cpp \ + ../../../src/ui/uiStyleModel.cpp \ + ../../../src/ui/uiNodesItemModel.cpp + +unix{ + QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter + TEMPLATE = lib + UI_DIR = .ui + MOC_DIR = .moc + OBJECTS_DIR = .obj + DEFINES += QANAVA_LINUX +} +win32{ + TEMPLATE = vclib + QMAKE_MAKEFILE = ui.vcproj + OBJECTS_DIR = ./Debug +} + ============================================================ --- libs/qanava/build/pro/ui/ui.vcproj 27556f6c5e8220426de2981781da91d437c0d70a +++ libs/qanava/build/pro/ui/ui.vcproj 27556f6c5e8220426de2981781da91d437c0d70a @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ============================================================ --- libs/qanava/build/pro/utl/utl.pro c4512de66632bff5f9e08c402321a20d9787b60e +++ libs/qanava/build/pro/utl/utl.pro c4512de66632bff5f9e08c402321a20d9787b60e @@ -0,0 +1,28 @@ +SOURCES += ../../../src/utl/utlProgress.cpp +HEADERS += ../../../src/utl/utlManager.hpp \ + ../../../src/utl/utlConfig.h \ + ../../../src/utl/utlProgress.h \ + ../../../src/utl/utlManager.h + +CONFIG += qt thread debug warn_on staticlib +DESTDIR = ../../ +LANGUAGE = C++ +TARGET = qanava_utl +DEFINES += QANAVA + +unix { + QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter + TEMPLATE = lib + UI_DIR = .ui + MOC_DIR = .moc + OBJECTS_DIR = .obj + DEFINES += QANAVA_LINUX +} +win32 { + TEMPLATE = vclib + QMAKE_MAKEFILE = utl.vcproj + OBJECTS_DIR = ./Debug +} + + + ============================================================ --- libs/qanava/build/pro/utl/utl.vcproj 850872df193be444b7c0957cabff2482643c7753 +++ libs/qanava/build/pro/utl/utl.vcproj 850872df193be444b7c0957cabff2482643c7753 @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ============================================================ --- libs/qanava/build/vc71/qanava.sln f0baa870483482865bc22f324064e1213adcedee +++ libs/qanava/build/vc71/qanava.sln f0baa870483482865bc22f324064e1213adcedee @@ -0,0 +1,124 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qanava_la", "..\pro\la\la.vcproj", "{E95EECC9-D33E-3C2A-8A7A-DAE3AE491664}" + ProjectSection(ProjectDependencies) = postProject + {D5044882-7CE3-3B34-A20B-CD746750C569} = {D5044882-7CE3-3B34-A20B-CD746750C569} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qanava_can", "..\pro\can\can.vcproj", "{AAE8FBE9-12BF-33C4-8A80-17D05269587A}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_qtmodel", "..\..\tests\qtmodel\test_qtmodel.vcproj", "{D769CC4A-F8B5-3D36-8D2B-A0B7E221D5F6}" + ProjectSection(ProjectDependencies) = postProject + {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664} = {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664} + {AAE8FBE9-12BF-33C4-8A80-17D05269587A} = {AAE8FBE9-12BF-33C4-8A80-17D05269587A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_basic", "..\..\tests\basic\test_basic.vcproj", "{0B9FE8EB-0588-3B7F-81C8-451D88AA7763}" + ProjectSection(ProjectDependencies) = postProject + {D5044882-7CE3-3B34-A20B-CD746750C569} = {D5044882-7CE3-3B34-A20B-CD746750C569} + {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664} = {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664} + {AAE8FBE9-12BF-33C4-8A80-17D05269587A} = {AAE8FBE9-12BF-33C4-8A80-17D05269587A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_logo", "..\..\tests\logo\test_logo.vcproj", "{BBCDCF1F-2033-3350-9B07-FFF3D852B3E3}" + ProjectSection(ProjectDependencies) = postProject + {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664} = {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664} + {AAE8FBE9-12BF-33C4-8A80-17D05269587A} = {AAE8FBE9-12BF-33C4-8A80-17D05269587A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_layout", "..\..\tests\layout\test_layout.vcproj", "{5B612C24-0FC9-3959-B0B9-2582E50B5004}" + ProjectSection(ProjectDependencies) = postProject + {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664} = {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664} + {AAE8FBE9-12BF-33C4-8A80-17D05269587A} = {AAE8FBE9-12BF-33C4-8A80-17D05269587A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qanava_utl", "..\pro\utl\utl.vcproj", "{D5044882-7CE3-3B34-A20B-CD746750C569}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_simpleqtmodel", "..\..\tests\simpleqtmodel\test_simpleqtmodel.vcproj", "{27409704-FB8E-39EF-AB9B-57B2A2E8FC7C}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_styles", "..\..\tests\styles\test_styles.vcproj", "{5946E743-5ECA-301C-B7E8-8F3492138804}" + ProjectSection(ProjectDependencies) = postProject + {2D49EB7C-664F-3221-A283-24A2AB39A01F} = {2D49EB7C-664F-3221-A283-24A2AB39A01F} + {D5044882-7CE3-3B34-A20B-CD746750C569} = {D5044882-7CE3-3B34-A20B-CD746750C569} + {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664} = {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664} + {AAE8FBE9-12BF-33C4-8A80-17D05269587A} = {AAE8FBE9-12BF-33C4-8A80-17D05269587A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qanava_ui", "..\pro\ui\ui.vcproj", "{2D49EB7C-664F-3221-A283-24A2AB39A01F}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_terror", "..\..\tests\terror\test_terror.vcproj", "{71DBBA2A-10D1-3DA3-888E-BB4B134939FA}" + ProjectSection(ProjectDependencies) = postProject + {2D49EB7C-664F-3221-A283-24A2AB39A01F} = {2D49EB7C-664F-3221-A283-24A2AB39A01F} + {D5044882-7CE3-3B34-A20B-CD746750C569} = {D5044882-7CE3-3B34-A20B-CD746750C569} + {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664} = {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664} + {AAE8FBE9-12BF-33C4-8A80-17D05269587A} = {AAE8FBE9-12BF-33C4-8A80-17D05269587A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_customnodes", "..\..\tests\customnodes\test_customnodes.vcproj", "{A53A62E0-F302-3AC8-95D7-EB695FF71D49}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664}.Debug.ActiveCfg = Debug|Win32 + {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664}.Debug.Build.0 = Debug|Win32 + {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664}.Release.ActiveCfg = Release|Win32 + {E95EECC9-D33E-3C2A-8A7A-DAE3AE491664}.Release.Build.0 = Release|Win32 + {AAE8FBE9-12BF-33C4-8A80-17D05269587A}.Debug.ActiveCfg = Debug|Win32 + {AAE8FBE9-12BF-33C4-8A80-17D05269587A}.Debug.Build.0 = Debug|Win32 + {AAE8FBE9-12BF-33C4-8A80-17D05269587A}.Release.ActiveCfg = Release|Win32 + {AAE8FBE9-12BF-33C4-8A80-17D05269587A}.Release.Build.0 = Release|Win32 + {D769CC4A-F8B5-3D36-8D2B-A0B7E221D5F6}.Debug.ActiveCfg = Debug|Win32 + {D769CC4A-F8B5-3D36-8D2B-A0B7E221D5F6}.Debug.Build.0 = Debug|Win32 + {D769CC4A-F8B5-3D36-8D2B-A0B7E221D5F6}.Release.ActiveCfg = Release|Win32 + {0B9FE8EB-0588-3B7F-81C8-451D88AA7763}.Debug.ActiveCfg = Debug|Win32 + {0B9FE8EB-0588-3B7F-81C8-451D88AA7763}.Debug.Build.0 = Debug|Win32 + {0B9FE8EB-0588-3B7F-81C8-451D88AA7763}.Release.ActiveCfg = Release|Win32 + {0B9FE8EB-0588-3B7F-81C8-451D88AA7763}.Release.Build.0 = Release|Win32 + {BBCDCF1F-2033-3350-9B07-FFF3D852B3E3}.Debug.ActiveCfg = Debug|Win32 + {BBCDCF1F-2033-3350-9B07-FFF3D852B3E3}.Debug.Build.0 = Debug|Win32 + {BBCDCF1F-2033-3350-9B07-FFF3D852B3E3}.Release.ActiveCfg = Release|Win32 + {5B612C24-0FC9-3959-B0B9-2582E50B5004}.Debug.ActiveCfg = Debug|Win32 + {5B612C24-0FC9-3959-B0B9-2582E50B5004}.Debug.Build.0 = Debug|Win32 + {5B612C24-0FC9-3959-B0B9-2582E50B5004}.Release.ActiveCfg = Release|Win32 + {D5044882-7CE3-3B34-A20B-CD746750C569}.Debug.ActiveCfg = Debug|Win32 + {D5044882-7CE3-3B34-A20B-CD746750C569}.Debug.Build.0 = Debug|Win32 + {D5044882-7CE3-3B34-A20B-CD746750C569}.Release.ActiveCfg = Release|Win32 + {D5044882-7CE3-3B34-A20B-CD746750C569}.Release.Build.0 = Release|Win32 + {27409704-FB8E-39EF-AB9B-57B2A2E8FC7C}.Debug.ActiveCfg = Debug|Win32 + {27409704-FB8E-39EF-AB9B-57B2A2E8FC7C}.Debug.Build.0 = Debug|Win32 + {27409704-FB8E-39EF-AB9B-57B2A2E8FC7C}.Release.ActiveCfg = Release|Win32 + {27409704-FB8E-39EF-AB9B-57B2A2E8FC7C}.Release.Build.0 = Release|Win32 + {5946E743-5ECA-301C-B7E8-8F3492138804}.Debug.ActiveCfg = Debug|Win32 + {5946E743-5ECA-301C-B7E8-8F3492138804}.Debug.Build.0 = Debug|Win32 + {5946E743-5ECA-301C-B7E8-8F3492138804}.Release.ActiveCfg = Release|Win32 + {5946E743-5ECA-301C-B7E8-8F3492138804}.Release.Build.0 = Release|Win32 + {2D49EB7C-664F-3221-A283-24A2AB39A01F}.Debug.ActiveCfg = Debug|Win32 + {2D49EB7C-664F-3221-A283-24A2AB39A01F}.Debug.Build.0 = Debug|Win32 + {2D49EB7C-664F-3221-A283-24A2AB39A01F}.Release.ActiveCfg = Release|Win32 + {2D49EB7C-664F-3221-A283-24A2AB39A01F}.Release.Build.0 = Release|Win32 + {71DBBA2A-10D1-3DA3-888E-BB4B134939FA}.Debug.ActiveCfg = Debug|Win32 + {71DBBA2A-10D1-3DA3-888E-BB4B134939FA}.Debug.Build.0 = Debug|Win32 + {71DBBA2A-10D1-3DA3-888E-BB4B134939FA}.Release.ActiveCfg = Release|Win32 + {71DBBA2A-10D1-3DA3-888E-BB4B134939FA}.Release.Build.0 = Release|Win32 + {A53A62E0-F302-3AC8-95D7-EB695FF71D49}.Debug.ActiveCfg = Debug|Win32 + {A53A62E0-F302-3AC8-95D7-EB695FF71D49}.Debug.Build.0 = Debug|Win32 + {A53A62E0-F302-3AC8-95D7-EB695FF71D49}.Release.ActiveCfg = Release|Win32 + {A53A62E0-F302-3AC8-95D7-EB695FF71D49}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal ============================================================ --- libs/qanava/licence.txt caeb68c46fa36651acf592771d09de7937926bb3 +++ libs/qanava/licence.txt caeb68c46fa36651acf592771d09de7937926bb3 @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This 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 + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + ============================================================ --- libs/qanava/qanava.pro 724ad04ac46172941865f341becdbd98a4d362d8 +++ libs/qanava/qanava.pro 724ad04ac46172941865f341becdbd98a4d362d8 @@ -0,0 +1,3 @@ +TEMPLATE=subdirs +SUBDIRS=build + ============================================================ --- libs/qanava/readme.txt 57df6d534b3a5cdd1bbcae44047f0ba67377f170 +++ libs/qanava/readme.txt 57df6d534b3a5cdd1bbcae44047f0ba67377f170 @@ -0,0 +1,65 @@ +Qanava v0.0.10 +Copyright (C) 2005-2006 Benoit AUTHEMAN address@hidden + +LICENCE: + +Qanava is distributed under the GNU LESSER GENERAL PUBLIC LICENSE (GNU LGPL v2.1) +Licence is detailed in the LICENCE.txt file. + + +BUILD: + +For Windows 2000/XP: Open the build/vc71/qanava.sln Visual Studio 2001 (or later) solution file, then build the solution. MSVC 2005 is not officially supported, you will have to re-generate all projects files by running qmake in 'pro' and 'tests' subdirectories. You eventually will have to generate all projects files in 'build/pro' using 'qmake' command. + +For Linux, just generate makefiles with the 'qmake' command, and launch the build with 'make'. The compilation has been tested successfully with GCC 4.0.1 and QT 4.2.0 PR1 or later. + +There are no dependencies outside of Trolltech QT. + +Qanava is primarily developed on Windows 2000 with QT 4.2.0 PR1. + + +INSTALLATION: + +There is currently no automated installation system, just use the 'qmake' command to generate makefiles, and gmake to build both the library and samples. + + +USING QANAVA / BUGS / PROBLEMS / etc. + +For any problem related to Qanava, mail 'address@hidden' or post a comment on: +http://www.libqanava.org/ + +If you did test Qanava, please send some feedback (even short!) by mail or via a comment. + +I would also be interested in supporting the use of Qanava in an open source project, eventually adding specific features and dealing with problems that might occurs. + + +RELEASE NOTES: + +v0.0.10: (06/09/29) Qanava is now using QT 4.2.0 and the new GraphicsView framework. Custom nodes attributes can now be added to nodes trough the graph interface. A library was created as a repository for widgets used to display graph features, such as styles or nodes list. An abstract factory system now allows the registration of custom nodes to be displayed in the graph view. New samples were added to demonstrate styles modifications, and how to display custom nodes attributes (9/11 social graph). + +v0.0.8b: (06/06/09) Serious bugs in GraphItemView and GraphItemModel were fixed. Better support for GCC compilation. Qanava now work with the latest KDE4 qt-copy (qt 4.1.3). + +v0.0.8: (16/05/02) Qanava now support a full set of features (insertion/suppression/edition) to modify its graph, and all modification are reflected to and from to Interview model. Qanava is now distributed under the GNU LGPL. + +v0.0.7: (06/04/02) Qanava no longer depend on QCanvas and does all its drawing as a standalone widget using Arthur. Model/view system now supports on the fly node insertion and suppression. Grid architecture has been cleaned, and the usual regular grid can now be changed with a check board one. The rendering code has received numerous optimisations and the UI is now much more reactive than with QCanvas code. This is the first version that is stable enough version to be considered useable as a library in "unstable" code. + +v0.0.6: (06/03/11) Qanava now use QtCanvas (the qt4 port of Q3Canvas), and no longer require the qt3support library (do not forget to copy qtcanvas.cpp and qtcanvas.h from your QT installation to the src/can directory). + +v0.0.5: (06/01/09) Qanava has the same canvas problems than in v0.0.4. Q3Canvas in Qt 4.1 is better than in Qt 4.0.1, but still far from being as fast and bug free than in Qt 3. This serious canvas problem cannot be addressed until Trolltech release their new canvas system in Qt 4.2.0. + +v0.0.4: (05/11/29) While Qanava is now a qt4 library, the old QCanvas class is still used for graphic rendering until the new qt4 canvas system is released with qt4.1 (even if there is no such system be in the preview release, hum...). The support for the old canvas in qt 4.0.1 is extremely slow, and seems to be seriously buggy (clipping and zoom problems). The X11 version of Q3Canvas seems to be less affected than win32, anyways, Qanava v0.0.4 should be considered a transition release until the display 'backend' is stabilized (either using Arthur, or hopefully a new graphic canvas). + + +NO WARRANTY + + BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + ============================================================ --- libs/qanava/src/can/canController.cpp 3e27498d50aa0b884f20990971fd2d96dbab9c76 +++ libs/qanava/src/can/canController.cpp 3e27498d50aa0b884f20990971fd2d96dbab9c76 @@ -0,0 +1,531 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canController.cpp +// \author Benoit Autheman (address@hidden) +// \date 2003 August 13 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "canController.h" +#include "canGraphicsView.h" + + +// QT headers +#include +#include +#include +#include +#include +#include +#include + + +namespace qan { // ::qan +namespace can { // ::qan::can + + +bool Controller::Manager::keyPressEvent( QKeyEvent* e ) +{ + for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ ) + { + if ( ( *controllerIter )->keyPressEvent( e ) ) + return true; + } + return false; +} + +bool Controller::Manager::mousePressEvent( QMouseEvent* e ) +{ + for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ ) + { + if ( ( *controllerIter )->mousePressEvent( e ) ) + return true; + } + return false; +} + +bool Controller::Manager::mouseReleaseEvent( QMouseEvent* e ) +{ + for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ ) + { + if ( ( *controllerIter )->mouseReleaseEvent( e ) ) + return true; + } + return false; +} + +bool Controller::Manager::mouseMoveEvent( QMouseEvent* e ) +{ + for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ ) + { + if ( ( *controllerIter )->mouseMoveEvent( e ) ) + return true; + } + return false; +} + +bool Controller::Manager::mouseDoubleClickEvent( QMouseEvent* e ) +{ + for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ ) + { + if ( ( *controllerIter )->mouseDoubleClickEvent( e ) ) + return true; + } + return false; +} + +bool Controller::Manager::wheelEvent( QWheelEvent* e ) +{ + for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ ) + { + if ( ( *controllerIter )->wheelEvent( e ) ) + return true; + } + return false; +} + +Controller* Controller::Manager::getController( QString name ) +{ + for ( Controller::Manager::iterator controllerIter = begin( ); controllerIter != end( ); controllerIter++ ) + { + if ( ( *controllerIter )->getName( ) == name ) + return ( *controllerIter ); + } + return 0; +} + +void Controller::Manager::registerController( Controller* controller ) +{ + if ( controller == 0 ) + return; + + add( *controller ); + QAction* controllerAction = controller->getAction( ); + if ( controllerAction->isCheckable( ) ) + _actionGroup->addAction( controllerAction ); // Only one checkable action active at a time +} + +Controller::Controller( QString name, GraphicsView& graphicsView ) : + _graphicsView( graphicsView ), + _action( 0 ), + _name( name ) +{ + +} + + +/* PanController Constructor/Destructor *///----------------------------------- +PanController::PanController( GraphicsView& graphicsView ) : + Controller( "pan_controller", graphicsView ), + _keyboardNavigation( true ), + _keyboardNavigationIntensity( 10.0 ), + _start( 0., 0. ) +{ + QAction* action = new QAction( this ); + action->setCheckable( true ); + action->setText( "Pan" ); + action->setVisible( true ); + action->setIcon( QIcon( "images/qanava_pan.png" ) ); + connect( action, SIGNAL( toggled( bool ) ), this, SLOT( toggled( bool ) ) ); + setAction( action ); + + setKeyboardNavigation( true ); +} + +void PanController::toggled( bool state ) +{ + setMode( state ? PAN : NONE ); +} +//----------------------------------------------------------------------------- + + + +/* PanController Keyboard Management *///-------------------------------------- +bool PanController::keyPressEvent( QKeyEvent* e ) +{ + getGraphicsView( ).setFocusPolicy( Qt::ClickFocus ); + if ( getKeyboardNavigation( ) ) + { + switch ( e->key( ) ) + { + case Qt::Key_Left: + getGraphicsView( ).translate( ( int )-_keyboardNavigationIntensity, 0 ); + break; + + case Qt::Key_Up: + getGraphicsView( ).translate( 0, ( int )-_keyboardNavigationIntensity ); + break; + + case Qt::Key_Right: + getGraphicsView( ).translate( ( int )_keyboardNavigationIntensity, 0 ); + break; + + case Qt::Key_Down: + getGraphicsView( ).translate( 0, ( int )_keyboardNavigationIntensity ); + break; + + default: + e->ignore( ); + break; + } + } + return false; +} + +/*! To use keyboard navigation, ensure that this widget parent widget has at least a 'Click' + focus policy (in Designer or with the QWidget::setFocusPolicy() method). +*/ +void PanController::setKeyboardNavigation( bool state ) +{ + _keyboardNavigation = state; + if ( state ) + { + getGraphicsView( ).viewport( )->setFocusPolicy( Qt::StrongFocus ); + getGraphicsView( ).setFocusPolicy( Qt::StrongFocus ); + } +} +//----------------------------------------------------------------------------- + + + +/* PanController Mouse Management *///----------------------------------------- +bool PanController::mousePressEvent( QMouseEvent* e ) +{ + // Navigation must not occurs if a node is under the mouse + QPointF p = getGraphicsView( ).mapToScene( e->pos( ) ); + QList< QGraphicsItem* > items = getGraphicsView( ).scene( )->items( p ); + if ( items.size( ) == 0 ) + { // TODO: prendre les elements de grille en compte (et tous ceux qui ne sont pas manipulables) + if ( getMode( ) == PAN ) + { + _start = e->pos( ); + getGraphicsView( ).viewport( )->setCursor( QCursor( Qt::SizeAllCursor ) ); + setState( PANNING ); + return true; + } + } + + return false; +} + +bool PanController::mouseReleaseEvent( QMouseEvent* e ) +{ + getGraphicsView( ).viewport( )->setCursor( QCursor( Qt::ArrowCursor ) ); + + if ( getMode( ) == PAN && getState( ) == PANNING ) + setState( NONE ); // Stop panning until next click + + return false; +} + +bool PanController::mouseMoveEvent( QMouseEvent* e ) +{ + if ( getMode( ) == PAN && getState( ) == PANNING ) + { + QPointF p = e->pos( ); // No mapping, we move scrollbars in their coordinate system + //QPointF p = getGraphicsView( ).mapToScene( e->pos( ) ); + + double accel = 1.0; + double dx = ( _start.x( ) - p.x( ) ) * accel; + double dy = ( _start.y( ) - p.y( ) ) * accel; + + int valueY = ( int )( getGraphicsView( ).verticalScrollBar( )->value( ) + dy ); + getGraphicsView( ).verticalScrollBar( )->setValue( valueY ); + int valueX = ( int )( getGraphicsView( ).horizontalScrollBar( )->value( ) + dx ); + getGraphicsView( ).horizontalScrollBar( )->setValue( valueX ); + + _start = p; + return true; + } + return false; +} +//----------------------------------------------------------------------------- + + + +/* ZoomWindowController Constructor/Destructor *///------------------------------- +ZoomWindowController::ZoomWindowController( GraphicsView& graphicsView ) : + Controller( "zoom_window_controller", graphicsView ), + _start( 0., 0. ), + _zoomRectItem( 0 ) +{ + QAction* action = new QAction( this ); + action->setCheckable( true ); + action->setText( "Zoom Window" ); + action->setVisible( true ); + action->setIcon( QIcon( "images/qanava_zoomwindow.png" ) ); + connect( action, SIGNAL( toggled( bool ) ), this, SLOT( toggled( bool ) ) ); + setAction( action ); + + _zoomRectItem = new QGraphicsRectItem( QRectF( 0., 0., 50., 50. ), 0, getGraphicsView( ).scene( ) ); + _zoomRectItem->setZValue( 100. ); + QPen p; + p.setStyle( Qt::DotLine ); + p.setWidth( 1 ); + p.setColor( QColor( 55, 55, 55 ) ); + _zoomRectItem->setPen( p ); + _zoomRectItem->hide( ); +} + +void ZoomWindowController::toggled( bool state ) +{ + setMode( state ? ZOOM : NONE ); +} +//----------------------------------------------------------------------------- + + + +/* ZoomWindowController Zooming Management *///-------------------------------- +bool ZoomWindowController::mousePressEvent( QMouseEvent* e ) +{ + // Navigation must not occurs if a node is under the mouse + QPointF p = getGraphicsView( ).mapToScene( e->pos( ) ); + QList< QGraphicsItem* > items = getGraphicsView( ).scene( )->items( p ); + if ( items.size( ) == 0 ) + { // TODO: prendre les elements de grille en compte (et tous ceux qui ne sont pas manipulables) + if ( getMode( ) == ZOOM ) + { + _start = getGraphicsView( ).mapToScene( e->pos( ) ); + setState( ZOOMING ); + return true; + } + } + + return false; +} + +bool ZoomWindowController::mouseReleaseEvent( QMouseEvent* e ) +{ + if ( getMode( ) == ZOOM && getState( ) == ZOOMING ) + { + getGraphicsView( ).fitInView( _zoomRectItem->rect( ), Qt::KeepAspectRatioByExpanding ); + _zoomRectItem->hide( ); + setState( NONE ); // Stop zooming until next click + return true; + } + + return false; +} + +bool ZoomWindowController::mouseMoveEvent( QMouseEvent* e ) +{ + if ( getMode( ) == ZOOM && getState( ) == ZOOMING && _zoomRectItem != 0 ) + { + QPointF p = getGraphicsView( ).mapToScene( e->pos( ) ); + + QRectF r( _start.x( ), _start.y( ), + p.x( ) - _start.x( ), p.y( ) - _start.y( ) ); + _zoomRectItem->setRect( r ); + _zoomRectItem->show( ); + return true; + } + return false; +} +//----------------------------------------------------------------------------- + + + +/* ZoomController Constructor/Destructor *///---------------------------------- +ZoomController::ZoomController( GraphicsView& graphicsView ) : + Controller( "zoom_controller", graphicsView ), + _actionZoomIn( new QAction( this ) ), + _actionZoomOut( new QAction( this ) ) +{ + QAction* action = new QAction( this ); + action->setCheckable( true ); + action->setText( "Zoom" ); + action->setVisible( true ); + action->setIcon( QIcon( "images/qanava_zoom.png" ) ); + setAction( action ); + + _actionZoomIn->setText( "Zoom In" ); + _actionZoomIn->setVisible( true ); + _actionZoomIn->setIcon( QIcon( "images/qanava_zoomin.png" ) ); + connect( _actionZoomIn, SIGNAL( triggered( bool ) ), this, SLOT( zoomIn( bool ) ) ); + + _actionZoomOut->setText( "Zoom Out" ); + _actionZoomOut->setVisible( true ); + _actionZoomOut->setIcon( QIcon( "images/qanava_zoomout.png" ) ); + connect( _actionZoomOut, SIGNAL( triggered( bool ) ), this, SLOT( zoomOut( bool ) ) ); +} +//----------------------------------------------------------------------------- + + + +/* ZoomController Zooming Management *///-------------------------------------- +void ZoomController::zoomIn( bool state ) +{ + getGraphicsView( ).setZoom( getGraphicsView( ).getZoom( ) + 0.2 ); +} + +void ZoomController::zoomOut( bool state ) +{ + getGraphicsView( ).setZoom( getGraphicsView( ).getZoom( ) - 0.2 ); +} + +bool ZoomController::wheelEvent( QWheelEvent* e ) +{ + return false; +} + +QAction* ZoomController::getAction( QString name ) +{ + if ( name == "zoom_in" ) + return _actionZoomIn; + else if ( name == "zoom_out" ) + return _actionZoomOut; + + return 0; +} +//----------------------------------------------------------------------------- + + + +/* Selection Controller Management *///------------------------------------------ +/*SelectionController::SelectionController( GraphicsView& graphicsView ) : + Controller( graphicsView ) +{ +} + +bool SelectionController::mouseDoubleClickEvent( QMouseEvent* e ) +{*/ + // FIXME +/* QPointF p = getGraphicsView( ).mapToScene( e->pos( ) ); + Item::List collisions; + getGraphicsView( ).getCanvas( )->getCollisions( p, collisions ); + for ( Item::List::iterator itemIter = collisions.begin( ); itemIter != collisions.end( ); itemIter++ ) + { + Item* item = *itemIter; + if ( getGraphicsView( ).getCanvas( )->isFreed( item ) ) + break; + + la::Node* node = getGraphicsView( ).getGraphicItemNode( item ); + if ( node != 0 ) + emit nodeSelected( node, p ); + }*/ + +/* return false; +}*/ +//----------------------------------------------------------------------------- + + + +/* Tooltip Controller Management *///-------------------------------------------- +/*TooltipController::TooltipController( GraphicsView& graphicsView ) : + Controller( graphicsView ), + //_tipItem( 0 ), + _tipPos( 0, 0 ), + _timer( 0 ) +{ + _timer = new QTimer( this ); + connect( _timer, SIGNAL( timeout( ) ), SLOT( tipTimeout( ) ) ); +}*/ + +/*void TooltipController::tipTimeout( ) +{*/ + // FIXME + // Don't show tooltips in case of error or if another controller is already active +/* if ( _tipItem == 0 || getGraphicsView( ).getControllerManager( ).isControllerActive( ) ) + { + _timer->stop( ); + return; + } + + // Test if the mouse is still on the item that has started the tooltip demand (tooltip delay) milliseconds ago + Item::List collisions; + getGraphicsView( ).getCanvas( )->getCollisions( _tipPos, collisions ); + for ( Item::List::iterator itemIter = collisions.begin( ); itemIter != collisions.end( ); itemIter++ ) + { + Item* item = *itemIter; + + if ( item == _tipItem ) + { + la::Node* node = getGraphicsView( ).getGraphicItemNode( _tipItem ); + if ( node != 0 ) + { + // Compute the real screen viewport coordinates + QPoint viewportTipPosContent = getGraphicsView( ).mapFromCanvas( _tipPos ); + emit nodeTipped( node, getGraphicsView( ).viewport( )->mapToGlobal( viewportTipPosContent ) ); + } + } + } + _timer->stop( ); + _tipItem = 0;*/ +//} + +//bool TooltipController::mouseMoveEvent( QMouseEvent* e ) +//{ + // FIXME +/* QPointF p = getGraphicsView( ).mapToScene( e->pos( ) ); + _tipPos = p; + + // If no button is pressed, there is no manipulation or navigation operation going on, so tooltip can be displayed + if ( e->button() != Qt::LeftButton ) + { + Item::List collisions; + getGraphicsView( ).getCanvas( )->getCollisions( _tipPos, collisions ); + for ( Item::List::iterator itemIter = collisions.begin( ); itemIter != collisions.end( ); itemIter++ ) + { + Item* item = *itemIter; + if ( item == _tipItem && _timer->isActive( ) ) // Avoid the timer to be restarted when moving in the same item + break; + + _tipPos = p; + if ( getGraphicsView( ).getCanvas( )->isFreed( item ) ) + break; + + la::Node* node = getGraphicsView( ).getGraphicItemNode( item ); + if ( node != 0 ) + { + _timer->start( 800 ); + _tipItem = item; + return true; + } + break; // Take just the first intersecting item to avoid deep z selection + } + } + else + { + // There is a complex navigation or manipulation operation going on, don't display tooltips + _timer->stop( ); + _tipItem = 0; + } + */ +// return false; +//} + +//bool TooltipController::mouseDoubleClickEvent( QMouseEvent* e ) +//{ + // Avoid interference with other controllers (such as simultaneous tip and double click node selection) + // FIXME + /*_timer->stop( ); + _tipItem = 0;*/ +// return false; +//} +//----------------------------------------------------------------------------- + + +} // ::qan::can +} // ::qan + ============================================================ --- libs/qanava/src/can/canController.h 8bf4163cd12f695e4aaf5c96559f9b9b8cefd1b2 +++ libs/qanava/src/can/canController.h 8bf4163cd12f695e4aaf5c96559f9b9b8cefd1b2 @@ -0,0 +1,351 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canController.h +// \author Benoit Autheman (address@hidden) +// \date 2003 August 13 +//----------------------------------------------------------------------------- + + +#ifndef canController_h +#define canController_h + + +// Qanava headers +#include "../la/laNode.h" +#include "../utl/utlManager.h" + + +// STD headers +#include + + +// QT headers +#include +#include +#include +#include +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan +namespace can { // ::qan::can + + class GraphicsView; + + //! Manage complex view modification operations in an AbstractItemView object (for example, panning, selection, etc.). + /*! + \nosubgrouping + */ + class Controller : public QObject + { + Q_OBJECT + + public: + + class Manager : public utl::Manager< Controller > + { + public: + + Manager( QObject* parent ) : _actionGroup( new QActionGroup( parent ) ) { } + + virtual bool keyPressEvent( QKeyEvent* e ); + + virtual bool mousePressEvent( QMouseEvent* e ); + + virtual bool mouseReleaseEvent( QMouseEvent* e ); + + virtual bool mouseMoveEvent( QMouseEvent* e ); + + virtual bool mouseDoubleClickEvent( QMouseEvent* e ); + + virtual bool wheelEvent( QWheelEvent* e ); + + void registerController( Controller* controller ); + + Controller* getController( QString name ); + + private: + + QActionGroup* _actionGroup; + }; + + Controller( QString name, GraphicsView& graphicsView ); + + virtual bool keyPressEvent( QKeyEvent* e ) { return false; } + + virtual bool mousePressEvent( QMouseEvent* e ) { return false; } + + virtual bool mouseReleaseEvent( QMouseEvent* e ) { return false; } + + virtual bool mouseMoveEvent( QMouseEvent* e ) { return false; } + + virtual bool mouseDoubleClickEvent( QMouseEvent* e ) { return false; } + + virtual bool wheelEvent( QWheelEvent* e ) { return false; } + + QString getName( ) { return _name; } + + protected: + + GraphicsView& getGraphicsView( ) { return _graphicsView; } + + private: + + GraphicsView& _graphicsView; + + QAction* _action; + + QString _name; + + protected: + + void setAction( QAction* action ) { _action = action; } + + public: + + //! Get a custom action by name in this controller. + virtual QAction* getAction( QString name ) { return 0; } + + public slots: + + QAction* getAction( ) { return _action; } + + signals: + + //! Emmitted when the controller action (must) state changes. + void toggled( bool on ); + }; + + + + //! . + /*! + \nosubgrouping + */ + class PanController : public Controller + { + Q_OBJECT + + /*! \name PanController Constructor/Destructor *///-------------------- + //@{ + public: + + //! PanController constructor with associed graphics view initialization. + PanController( GraphicsView& graphicsView ); + + //! PanController virtual destructor. + virtual ~PanController( ) { } + //@} + //--------------------------------------------------------------------- + + + //! . + enum State + { + NONE = 0, + KEYBOARD = 1, + PAN = 2, + PANNING = 8, + }; + + /*! \name Keyboard Navigation Management *///-------------------------- + //@{ + public: + + //! . + virtual bool keyPressEvent( QKeyEvent* e ); + + //! Enable or disable keyboard navigation (with arrow keys). + void setKeyboardNavigation( bool state ); + + //! Get the current keyboard navigation state. + bool getKeyboardNavigation( ) const { return _keyboardNavigation; } + + private: + + //! Keyboard navigation state. + bool _keyboardNavigation; + + //! Keyboard navigation intensity. + double _keyboardNavigationIntensity; + //@} + //--------------------------------------------------------------------- + + + + /*! \name Panning and Zooming Management *///-------------------------- + //@{ + public: + virtual bool mousePressEvent( QMouseEvent* e ); + + virtual bool mouseReleaseEvent( QMouseEvent* e ); + + virtual bool mouseMoveEvent( QMouseEvent* e ); + + public: + + State getMode( ) const { return _mode; } + + State getState( ) const { return _state; } + + void setState( State state ) { _state = state; } + + void setMode( State mode ) { _mode = mode; } + + protected slots: + + void toggled( bool state ); + + private: + + //! . + QPointF _start; + + State _mode; + + State _state; + //@} + //--------------------------------------------------------------------- + }; + + + //! + /*! + \nosubgrouping + */ + class ZoomWindowController : public Controller + { + Q_OBJECT + + /*! \name ZoomWindowController Constructor/Destructor *///------------- + //@{ + public: + + //! ZoomWindowController constructor with associed graphics view initialization. + ZoomWindowController( GraphicsView& graphicsView ); + + //! ZoomWindowController virtual destructor. + virtual ~ZoomWindowController( ) { } + //@} + //--------------------------------------------------------------------- + + //! . + enum State + { + NONE = 0, + ZOOM = 4, + ZOOMING = 16 + }; + + /*! \name Panning and Zooming Management *///-------------------------- + //@{ + public: + + virtual bool mousePressEvent( QMouseEvent* e ); + + virtual bool mouseReleaseEvent( QMouseEvent* e ); + + virtual bool mouseMoveEvent( QMouseEvent* e ); + + public: + + State getMode( ) const { return _mode; } + + State getState( ) const { return _state; } + + void setState( State state ) { _state = state; } + + void setMode( State mode ) { _mode = mode; } + + protected slots: + + void toggled( bool state ); + + private: + + //! . + QPointF _start; + + //! Geometric item used to model the dashed zoom selection window . + QGraphicsRectItem* _zoomRectItem; + + State _mode; + + State _state; + //@} + //--------------------------------------------------------------------- + }; + + + //! + /*! + \nosubgrouping + */ + class ZoomController : public Controller + { + Q_OBJECT + + /*! \name ZoomController Constructor/Destructor *///------------------- + //@{ + public: + + //! ZoomController constructor with associed graphics view initialization. + ZoomController( GraphicsView& graphicsView ); + + //! ZoomController virtual destructor. + virtual ~ZoomController( ) { } + //@} + //--------------------------------------------------------------------- + + + + /*! \name Panning and Zooming Management *///-------------------------- + //@{ + public: + + virtual bool wheelEvent( QWheelEvent* e ); + + virtual QAction* getAction( QString name ); + + protected slots: + + void zoomIn( bool state ); + + void zoomOut( bool state ); + + private: + + QAction* _actionZoomIn; + + QAction* _actionZoomOut; + //@} + //--------------------------------------------------------------------- + }; +} // ::qan::can +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // canController_h + ============================================================ --- libs/qanava/src/can/canGraphItemModel.cpp 1574e9b6984daf1de4e9b9168e8517dafc794b39 +++ libs/qanava/src/can/canGraphItemModel.cpp 1574e9b6984daf1de4e9b9168e8517dafc794b39 @@ -0,0 +1,433 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canGraphItemModel.h +// \author Benoit Autheman (address@hidden) +// \date 2005 November 22 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "./canStyle.h" +#include "./canGraphItemModel.h" + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan +namespace can { // ::qan::can + + +/* QT Model Interface Management *///------------------------------------------ +GraphItemModel::GraphItemModel( la::Graph& graph ) : + QAbstractItemModel( ), + _graph( graph ), + _styleManager( 0 ) +{ + // Add a graph listenner + GraphItemListener* listener = new can::GraphItemListener( graph ); + _graph.addListener( listener ); + + connect( listener, SIGNAL( nodeInsertedBeginSig(qan::la::Node&) ), this, SLOT( nodeInsertedBegin(qan::la::Node&) ) ); + connect( listener, SIGNAL( nodeInsertedSig(qan::la::Node&) ), this, SLOT( nodeInserted(qan::la::Node&) ) ); + connect( listener, SIGNAL( nodeRemovedBeginSig(qan::la::Node&) ), this, SLOT( nodeRemovedBegin(qan::la::Node&) ) ); + connect( listener, SIGNAL( nodeRemovedSig(qan::la::Node&) ), this, SLOT( nodeRemoved(qan::la::Node&) ) ); + connect( listener, SIGNAL( nodeChangedSig(qan::la::Node&) ), this, SLOT( nodeChanged(qan::la::Node&) ) ); + + // Generate persistent model indexes for all graph nodes + la::Node::Set marked; + la::Node::List::iterator nodeIter = _graph.getRootNodes( ).begin( ); + for ( int row = 0; nodeIter != _graph.getRootNodes( ).end( ); row++, nodeIter++ ) + { + int column = 0; + la::Node* node = *nodeIter; + visit( row, column, *node, marked, 500 ); + } +} + +void GraphItemModel::visit( int row, int column, la::Node& node, la::Node::Set& marked, int maxDepth ) +{ + if ( maxDepth == 0 ) + return; + + if ( marked.find( &node ) != marked.end( ) ) + return; + marked.insert( &node ); + + QModelIndex nodeIndex = createIndex( row, column, &node ); + QPersistentModelIndex* nodePersistentIndex = getNodePersistentIndex( &node ); + + if ( nodePersistentIndex != 0 ) + { + // Update a pre existing persistent index + changePersistentIndex( *nodePersistentIndex, nodeIndex ); + } + else + { + // Create a new persistent index + nodePersistentIndex = new QPersistentModelIndex( nodeIndex ); + _nodePersistentIndexMap.insert( std::pair< la::Node*, QPersistentModelIndex* >( &node, nodePersistentIndex ) ); + } + + column = 0; + maxDepth--; + + // visit sub nodes + la::Edge::List& edgeList = node.getOutEdges( ); + row = 0; + for ( la::Edge::List::iterator edgeIter = edgeList.begin( ); edgeIter != edgeList.end( ); edgeIter++ ) + { + la::Edge* edge = *edgeIter; + visit( row++, column, edge->getDst( ), marked, maxDepth ); + } +} + +QPersistentModelIndex* GraphItemModel::getNodePersistentIndex( la::Node* node ) const +{ + NodePersistentIndexMap::const_iterator nodeIter = _nodePersistentIndexMap.find( node ); + if ( nodeIter != _nodePersistentIndexMap.end( ) ) + return nodeIter->second; + return 0; +} + +QVariant GraphItemModel::data( const QModelIndex &index, int role ) const +{ + if ( !index.isValid( ) ) + return QVariant( "Index invalid" ); + + la::Node* node = static_cast< la::Node* >( index.internalPointer( ) ); + if ( node == 0 ) + return QVariant( ); + + const can::Style* style = 0; + if ( _styleManager != 0 && node != 0 ) + { + style = _styleManager->getStyle( node ); + if ( _styleManager->getStyle( node->getType( ) ) ) + style = _styleManager->getStyle( node->getType( ) ); + } + + QVariant result; + switch ( role ) + { + case Qt::DisplayRole: + result = node->getLabel( ).c_str( ); + break; + case Qt::DecorationRole: + if ( style != 0 && style->has( "icon" ) ) + { + QIcon icon( style->getIcon( "icon" ) ); + if ( !icon.isNull( ) ) + result = icon; + } + break; + case Qt::BackgroundColorRole: + { + if ( style != 0 && style->has( "backcolor" ) ) + { + QColor backColor = style->getColor( "backcolor" ); + if ( backColor.isValid( ) ) + { + QColor bc( backColor ); + bc.setAlpha( 50 ); + result = bc; + } + } + } + break; + case Qt::TextColorRole: + { + if ( style != 0 ) + { + QColor backColor = style->getColor( "textcolor" ); + if ( backColor.isValid( ) ) + result = backColor; + } + } + break; + + case Qt::UserRole + POSITION_X: + result = node->getPosition( )( 0 ); + break; + case Qt::UserRole + POSITION_Y: + result = node->getPosition( )( 1 ); + break; + case Qt::UserRole + DIMENSION_X: + result = node->getDimension( )( 0 ); + break; + case Qt::UserRole + DIMENSION_Y: + result = node->getDimension( )( 1 ); + break; + default: + break; + } + return result; +} + +bool GraphItemModel::hasChildren( const QModelIndex & parent ) const +{ + if ( !parent.isValid( ) ) + return ( _graph.getRootNodes( ).size( ) > 0 ); + else + { + la::Node* node = static_cast< la::Node* >( parent.internalPointer( ) ); + if ( node != 0 ) + return ( node->getOutEdges( ).size( ) > 0 ); + } + return false; +} + +Qt::ItemFlags GraphItemModel::flags( const QModelIndex& index ) const +{ + return ( Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled ); +} + +QModelIndex GraphItemModel::index(int row, int column, const QModelIndex &parent ) const +{ + if ( !parent.isValid( ) ) + { + la::Node::List::iterator nodeIter = _graph.getRootNodes( ).begin( ); + int n = 0; + for ( ; n < row && nodeIter != _graph.getRootNodes( ).end( ); n++, nodeIter++ ) { } + if ( n <= row && nodeIter != _graph.getRootNodes( ).end( ) ) + { + QPersistentModelIndex* index = getNodePersistentIndex( *nodeIter ); + return ( index != 0 ? QModelIndex( *index ) : QModelIndex( ) ); + } + } + else + { + la::Node* node = static_cast< la::Node* >( parent.internalPointer( ) ); + if ( node != 0 ) + { + la::Node::List outNodes; node->collectOutNodes( outNodes ); + la::Node::List::const_iterator outNodeIter = outNodes.begin( ); + int n = 0; + for ( ; n < row && outNodeIter != outNodes.end( ); n++, outNodeIter++ ) { } + + //-> n valid, mais iter=end, cas valide! + + if ( n <= row && outNodeIter != outNodes.end( ) ) + { + QPersistentModelIndex* persistentIndex = getNodePersistentIndex( *outNodeIter ); + return ( persistentIndex != 0 ? QModelIndex( *persistentIndex ) : QModelIndex( ) ); + } + } + } + return QModelIndex( ); +} + +QModelIndex GraphItemModel::parent( const QModelIndex &index ) const +{ + if ( !index.isValid( ) ) + return QModelIndex( ); + else + { + la::Node* node = static_cast< la::Node* >( index.internalPointer( ) ); + la::Node* superNode = 0; + if ( node != 0 && ( node->getInEdges( ).size( ) > 0 ) ) + superNode = &( *node->getInEdges( ).begin( ) )->getSrc( ); + + if ( superNode != 0 && superNode->getInEdges( ).size( ) > 0 ) + { + QPersistentModelIndex* index = getNodePersistentIndex( superNode ); + return ( index != 0 ? QModelIndex( *index ) : QModelIndex( ) ); + } + else if ( superNode != 0 ) + { + int row = 0; + la::Node::List::const_iterator nodeIter = _graph.getRootNodes( ).begin( ); + for ( ; nodeIter != _graph.getRootNodes( ).end( ); nodeIter++, row++ ) + { + if ( *nodeIter == superNode ) + break; + } + if ( nodeIter != _graph.getRootNodes( ).end( ) ) + { + QPersistentModelIndex* index = getNodePersistentIndex( superNode ); + return ( index != 0 ? QModelIndex( *index ) : QModelIndex( ) ); + } + } + } + return QModelIndex( ); +} + +int GraphItemModel::rowCount( const QModelIndex& parent ) const +{ + if ( !parent.isValid( ) ) + return _graph.getRootNodes( ).size( ); + else + { + la::Node* node = static_cast< la::Node* >( parent.internalPointer( ) ); + if ( node != 0 ) + return node->getOutEdges( ).size( ); + } + return 0; +} + +int GraphItemModel::columnCount( const QModelIndex& parent ) const +{ + return 1; +} + +bool GraphItemModel::setData ( const QModelIndex& index, const QVariant& value, int role ) +{ + if ( !index.isValid( ) ) + return true; + + if ( value.type( ) == QVariant::String ) + { + QString name = value.toString( ); + la::Node* node = static_cast< la::Node* >( index.internalPointer( ) ); + _graph.modifyNode( *node, name.toStdString( ), node->getType( ), _graph.findObject( node ) ); + } + return true; +} +//----------------------------------------------------------------------------- + +void GraphItemModel::nodeInsertedBegin( la::Node& node ) +{ + la::Node::List inNodes; node.collectInNodes( inNodes ); + if ( inNodes.size( ) == 0 ) // Root node + //beginInsertRows( QModelIndex( ), _graph.getRootNodes( ).size( ), _graph.getRootNodes( ).size( ) + 1 ); + emit rowsAboutToBeInserted( QModelIndex( ), _graph.getRootNodes( ).size( ), _graph.getRootNodes( ).size( ) + 1 ); + else + { + for ( la::Node::List::iterator inNodeIter = inNodes.begin( ); inNodeIter != inNodes.end( ); inNodeIter++ ) + { + la::Node* inNode = *inNodeIter; + QPersistentModelIndex* parentPersistentIndex = getNodePersistentIndex( inNode ); + QModelIndex parentIndex( parentPersistentIndex != 0 ? QModelIndex( *parentPersistentIndex ) : QModelIndex( ) ); + //beginInsertRows( parentIndex, inNode->getOutDegree( ) /*- 1*/, inNode->getOutDegree( ) /*- 1*/ + 1 ); + emit rowsAboutToBeInserted( parentIndex, inNode->getOutDegree( ) /*- 1*/, inNode->getOutDegree( ) /*- 1*/ + 1 ); + } + } +} + +void GraphItemModel::nodeInserted( la::Node& node ) +{ + la::Node::List inNodes; node.collectInNodes( inNodes ); + if ( inNodes.size( ) == 0 /*&& _graph.isRootNode( node )*/ ) + { + // Generate persistent model indexes for all graph root nodes + la::Node::Set marked; + la::Node::List::iterator nodeIter = _graph.getRootNodes( ).begin( ); + for ( int row = 0; nodeIter != _graph.getRootNodes( ).end( ); row++, nodeIter++ ) + { + int column = 0; + la::Node* node = *nodeIter; + visit( row, column, *node, marked, 1 ); + } + ////emit rowsInserted( QModelIndex( ), _graph.getRootNodes( ).size( ), _graph.getRootNodes( ).size( ) + 1 ); + emit rowsInserted( QModelIndex( ), _graph.getRootNodes( ).size( ) - 1, _graph.getRootNodes( ).size( ) ); + } + else + { + la::Node::Set marked; + int nodeRow = 0; + for ( la::Node::List::iterator inNodeIter = inNodes.begin( ); inNodeIter != inNodes.end( ); nodeRow++, inNodeIter++ ) + { + la::Node* inNode = *inNodeIter; + QPersistentModelIndex* parentPersistentIndex = getNodePersistentIndex( inNode ); + QModelIndex parentIndex( parentPersistentIndex != 0 ? QModelIndex( *parentPersistentIndex ) : QModelIndex( ) ); + + visit( parentIndex.row( ), 0, *inNode, marked, 2 ); + + QPersistentModelIndex* nodePersistentIndex = getNodePersistentIndex( &node ); + int nodeRow = 0; + if ( nodePersistentIndex != 0 && nodePersistentIndex->isValid( ) ) + nodeRow = nodePersistentIndex->row( ); + emit rowsInserted( parentIndex, nodeRow, nodeRow + 1 ); + } + } + +// endInsertRows( ); // Bug in QT 4.1.0 + //emit layoutChanged( ); +} + +void GraphItemModel::nodeRemovedBegin( la::Node& node ) +{ + NodePersistentIndexMap::iterator nodeIter = _nodePersistentIndexMap.find( &node ); + if ( nodeIter != _nodePersistentIndexMap.end( ) ) + { + QPersistentModelIndex* nodePersistentIndex = nodeIter->second; + int row = nodePersistentIndex->row( ); + QModelIndex parentIndex = nodePersistentIndex->parent( ); + //beginRemoveRows( parentIndex, row, row + 1 ); + emit rowsAboutToBeRemoved( parentIndex, row, row + 1 ); + } +} + +void GraphItemModel::nodeRemoved( la::Node& node ) +{ + QPersistentModelIndex* nodePersistentIndex = getNodePersistentIndex( &node ); + + // Adjust other concerned node model index (rows and columns index may now be invalid) + { + la::Node::List inNodes; node.collectInNodes( inNodes ); + if ( inNodes.size( ) == 0 ) // A removed node should always have no in or out nodes + { + // Generate persistent model indexes for all graph nodes + la::Node::Set marked; + la::Node::List::iterator nodeIter = _graph.getRootNodes( ).begin( ); + for ( int row = 0; nodeIter != _graph.getRootNodes( ).end( ); row++, nodeIter++ ) + { + int column = 0; + la::Node* node = *nodeIter; + visit( row, column, *node, marked, 1 ); + } + } + } + + _nodePersistentIndexMap.erase( &node ); + + QModelIndex parentIndex; + int nodeRow = 0; + if ( nodePersistentIndex != 0 ) + { + parentIndex = nodePersistentIndex->parent( ); + nodeRow = nodePersistentIndex->row( ); + } + + //if ( parentIndex.isValid( ) && nodeRow != -1 ) + if ( nodeRow != -1 ) + emit rowsRemoved( parentIndex, nodeRow, nodeRow + 1 ); + + //endRemoveRows( ); // Bug in QT 4.1.0 + emit layoutChanged( ); +} + +void GraphItemModel::nodeChanged( qan::la::Node& node ) +{ + QPersistentModelIndex* persistentNodeIndex = getNodePersistentIndex( &node ); + if ( persistentNodeIndex != 0 ) + { + QModelIndex nodeIndex( *persistentNodeIndex ); + if ( nodeIndex.isValid( ) ) + emit dataChanged( nodeIndex, nodeIndex ); + } +} + +} // ::qan::can +} // ::qan +//----------------------------------------------------------------------------- + + ============================================================ --- libs/qanava/src/can/canGraphItemModel.h 7488f5eddb6f46176ec2a43e281682acbd707f7e +++ libs/qanava/src/can/canGraphItemModel.h 7488f5eddb6f46176ec2a43e281682acbd707f7e @@ -0,0 +1,174 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canGraphItemModel.h +// \author Benoit Autheman (address@hidden) +// \date 2005 November 22 +//----------------------------------------------------------------------------- + + +#ifndef canGraphItemModel_h +#define canGraphItemModel_h + + +// Qanava headers +#include "../../src/la/laGraph.h" +#include "./canStyle.h" +//#include "../../src/can/canCanvas.h" + + +// QT headers +#include +#include +#include +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan + namespace can { // ::qan::can + + class GraphItemListener : public QObject, public la::Graph::Listener + { + Q_OBJECT + + public: + + GraphItemListener( la::Graph& graph, QObject* parent = 0 ) : QObject( parent ), la::Graph::Listener( graph ) { } + + virtual void nodeInsertedBegin( la::Node& node ) { emit nodeInsertedBeginSig( node ); } + + virtual void nodeInserted( la::Node& node ) { emit nodeInsertedSig( node ); } + + virtual void nodeRemovedBegin( la::Node& node ) { emit nodeRemovedBeginSig( node ); } + + virtual void nodeRemoved( la::Node& node ) { emit nodeRemovedSig( node ); } + + virtual void nodeChanged( la::Node& node ) { emit nodeChangedSig( node ); } + + signals: + + void nodeInsertedBeginSig( qan::la::Node& node ); + + void nodeInsertedSig( qan::la::Node& node ); + + void nodeRemovedBeginSig( qan::la::Node& node ); + + void nodeRemovedSig( qan::la::Node& node ); + + void nodeChangedSig( qan::la::Node& node ); + }; + + //! Provide access to a la::Graph trough a QT interview compatible interface. + /*! This model is useable with any classes based on QAbstractItemView, even if some + view might eventually not support (or have never been tested with) general graphs + with circular depedencies. + + \nosubgrouping + */ + class GraphItemModel : public QAbstractItemModel + { + Q_OBJECT + + public: + + //! Value to be added to the Qt::UserRole constant to get corresponding GraphItemModel data role. + enum DataRole + { + POSITION_X = 1, + POSITION_Y = 2, + DIMENSION_X = 3, + DIMENSION_Y = 4 + }; + + /*! \name QT Model Interface Management *///--------------------------- + //@{ + public: + + GraphItemModel( la::Graph& graph ); + + void visit( int row, int column, la::Node& node, la::Node::Set& marked, int maxDepth = 1 ); + + QPersistentModelIndex* getNodePersistentIndex( la::Node* node ) const; + + virtual QVariant data( const QModelIndex& index, int role ) const; + + virtual bool hasChildren( const QModelIndex & parent = QModelIndex( ) ) const; + + virtual Qt::ItemFlags flags( const QModelIndex& index ) const; + + virtual QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex( ) ) const; + + virtual QModelIndex parent( const QModelIndex& index ) const; + + virtual int rowCount( const QModelIndex& parent = QModelIndex( ) ) const; + + virtual int columnCount( const QModelIndex& parent = QModelIndex( ) ) const; + + virtual bool setData ( const QModelIndex& index, const QVariant& value, int role = Qt::EditRole ); + + virtual void reset( ) { QAbstractItemModel::reset( ); } + + void setStyleManager( can::Style::Manager* styleManager ) { _styleManager = styleManager; } + + typedef std::map< la::Node*, QPersistentModelIndex* > NodePersistentIndexMap; + + protected: + + NodePersistentIndexMap _nodePersistentIndexMap; + + la::Graph& _graph; + + can::Style::Manager* _styleManager; + //@} + //--------------------------------------------------------------------- + + signals: + + void rowsAboutToBeInserted( const QModelIndex& parent, int start, int end ); + + void rowsAboutToBeRemoved( const QModelIndex& parent, int start, int end ); + + void rowsInserted( const QModelIndex& parent, int start, int end ); + + void rowsRemoved( const QModelIndex& parent, int start, int end ); + + protected slots: + + virtual void nodeInsertedBegin( qan::la::Node& node ); + + virtual void nodeInserted( qan::la::Node& node ); + + virtual void nodeRemovedBegin( qan::la::Node& node ); + + virtual void nodeRemoved( qan::la::Node& node ); + + virtual void nodeChanged( qan::la::Node& node ); + }; + } // ::qan::can +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // canGraphItemModel_h + + ============================================================ --- libs/qanava/src/can/canGraphItemView.cpp 9f7d36b2ea896d61870bb1564cf3b3a52debb32f +++ libs/qanava/src/can/canGraphItemView.cpp 9f7d36b2ea896d61870bb1564cf3b3a52debb32f @@ -0,0 +1,643 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canGraphItemView.cpp +// \author Benoit Autheman (address@hidden) +// \date 2005 November 22 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "../la/laGraph.h" +#include "../la/laEdge.h" +#include "./canGraphItemView.h" +#include "./canGraphItemModel.h" +#include "./canGrid.h" + + +// STD headers +#include + + +// QT headers +#include +#include +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan +namespace can { // ::qan::can + + +/* View Construction *///------------------------------------------------------ +/*! + \param graph Already available graph used in this view GraphItemModel. + \param backgroundColor Graph canvas background color. + */ +GraphItemView::GraphItemView( QWidget* parent, la::Graph* graph, QColor backgroundColor, QSize size ) : + QAbstractItemView( parent ), + _graphicsScene( 0 ), + _graphicsView( 0 ), + _graph( graph ), + _layout( new la::Random( ) ) +{ + if ( _graph == 0 ) + _graph = new la::Graph( ); + + registerGraphicNodeFactory( new can::Node::DefaultFactory( ) ); + + _graphicsScene = new QGraphicsScene( this ); + _graphicsView = new GraphicsView( _graphicsScene, this ); + + QPalette palette; + palette.setColor( backgroundRole( ), backgroundColor ); + viewport( )->setPalette( palette ); + + setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); + setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded ); + + //viewport( )->setMouseTracking( true ); + //getCanvas( )->setMouseTracking( true ); // FIXME + + setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + + clear( ); + update( ); +} + +void GraphItemView::clear( ) +{ + // Clear all mappings + _modelIndexNodeMap.clear( ); + _modelIndexGraphicItemMap.clear( ); + _graphicItemModelIndexMap.clear( ); + _nodeGraphicItemMap.clear( ); + + // Clear al items in the graphic view + //_canvas->clear( ); // FIXME + + _styleManager.clear( ); + delete _layout; + _layout = new la::Random( ); +} +//----------------------------------------------------------------------------- + + + +/* QT View Interface Management *///------------------------------------------- +void GraphItemView::setModel ( QAbstractItemModel* model ) +{ + // Clear this view (we must clear before setting the new model since model will be set to 0) + clear( ); + + // Set the new model + QAbstractItemView::setModel( model ); + reset( ); +} + +QModelIndex GraphItemView::indexAt( const QPoint& p ) const +{ + return QModelIndex( ); +} + +void GraphItemView::visitModelIndex( QAbstractItemModel& model, QModelIndex& modelIndex, QModelIndex& parentIndex ) +{ + if ( GraphItemView::getModelIndexNode( modelIndex ) != 0 ) + return; + + if ( !modelIndex.isValid( ) ) + return; + + mapIndex( modelIndex, parentIndex ); + + if ( !model.hasChildren( modelIndex ) ) + return; + for ( int i = 0; i < model.rowCount( modelIndex ); i++ ) + { + QModelIndex index = model.index( i, 0, modelIndex ); + visitModelIndex( model, index, modelIndex ); + } +} + +void GraphItemView::mapIndex( QModelIndex& index, QModelIndex& parent ) +{ + if ( !index.isValid( ) ) + return; + + // Check if the index isn't already mapped + if ( _modelIndexNodeMap.find( index.internalPointer( ) ) != _modelIndexNodeMap.end( ) ) + return; + + if ( index.internalPointer( ) != 0 && _graph != 0 ) + { + // Map a model index to a graph node + la::Node* node = static_cast< la::Node* >( index.internalPointer( ) ); + if ( node == 0 || !_graph->hasNode( node ) ) + { + // Create a new graph node and map it + node = _graph->insertNode( "" ); + updateModelIndexNode( index, node ); + + // Create an edge between this node and its parent node + la::Node* parentNode = getModelIndexNode( parent ); + if ( node != 0 && parentNode != 0 ) + _graph->createEdge( *parentNode, *node ); + } + + + // Map a model index to a graphic item + if ( node != 0 ) + { + _modelIndexNodeMap.insert( std::pair< void*, la::Node* >( index.internalPointer( ), node ) ); + + // Get node type associed style + Style emptyStyle( "empty" ); + Style* style = &emptyStyle; + Style* advObjectStyle = _styleManager.getStyle( node ); + if ( advObjectStyle != 0 ) + style = advObjectStyle; + advObjectStyle = _styleManager.getStyle( node->getType( ) ); + if ( advObjectStyle != 0 ) + style = advObjectStyle; + + can::AbstractNode* nodeItem = 0; + if ( style != 0 ) + //nodeItem = new can::Node( _styleManager, *style, 0, _graphicsScene, QPoint( 1, 1 ), node->getLabel( ) ); + nodeItem = createGraphicNode( *node, _styleManager, *style, 0, _graphicsScene, QPoint( 1, 1 ), node->getLabel( ) ); + if ( nodeItem != 0 ) + { + // FIXME + //QRectF bb = nodeItem->computeBoundingRect( ); + //node->setDimension( bb.width( ), bb.height( ) ); + + _modelIndexGraphicItemMap.insert( std::pair< void*, can::AbstractNode* >( index.internalPointer( ), nodeItem ) ); + _nodeGraphicItemMap.insert( std::pair< la::Node*, can::AbstractNode* >( node, nodeItem ) ); + _graphicItemModelIndexMap.insert( std::pair< const QGraphicsItem*, void* >( nodeItem->getGraphicsItem( ), index.internalPointer( ) ) ); + } + + // Generate arrows for the model + la::Edge::Set edges; + std::copy( node->getInEdges( ).begin( ), node->getInEdges( ).end( ), std::inserter< la::Edge::Set >( edges, edges.begin( ) ) ); + std::copy( node->getOutEdges( ).begin( ), node->getOutEdges( ).end( ), std::inserter< la::Edge::Set >( edges, edges.begin( ) ) ); + for ( la::Edge::Set::iterator edgeIter = edges.begin( ); edgeIter != edges.end( ); edgeIter++ ) + { + la::Edge* edge = *edgeIter; + EdgeGraphicItemMap::iterator canvasEdgeIter = _edgeGraphicItemMap.find( edge ); + if ( canvasEdgeIter == _edgeGraphicItemMap.end( ) ) + { + can::Node* src = static_cast< can::Node* >( getNodeGraphicItem( &edge->getSrc( ) ) ); + can::Node* dst = static_cast< can::Node* >( getNodeGraphicItem( &edge->getDst( ) ) ); + if ( src != 0 && dst != 0 ) + { + can::Edge* edgeItem = new can::Edge( 0, _graphicsScene, src, dst/*, ( int )edge->getWeight( )*/ ); + _edgeGraphicItemMap.insert( std::pair< const la::Edge*, can::Edge* >( edge, edgeItem ) ); + } + } + else + canvasEdgeIter->second->show( ); // The arrow might have been previously hiden, so set it visible again + } + } + } +} + +void GraphItemView::updateModelIndexGraphicItem( QModelIndex& index ) +{ + if ( !index.isValid( ) ) + return; + +} + +/*! This method is usefull when this view model is a QT model (ex QDirModel) where items are + not internally mapped to an existing graph node. For example, if a node has just been + created for a specific model index, the notification mecanism of the model has eventually + not been used, this method can be used to force the associed node data update). + + \param index Item index in this view model that must be used to refresh its associed node internal data. + \param node Allow user to manually provide the node mapped to the given model item index. + */ +void GraphItemView::updateModelIndexNode( QModelIndex& index, la::Node* node ) +{ + if ( !index.isValid( ) ) + return; + + if ( index.column( ) != 0 ) + return; + + if ( node == 0 ) + node = getModelIndexNode( index ); + if ( node != 0 ) + { + std::string content( "" ); + double positionX( 0.0 ); + double positionY( 0.0 ); + double dimensionX( 75.0 ); + double dimensionY( 45.0 ); + + QVariant v = model( )->data( index, Qt::DisplayRole ); + content = std::string( v.type( ) == QVariant::String ? v.toString( ).toAscii( ) : "ERROR" ); + + v = model( )->data( index, Qt::UserRole + GraphItemModel::POSITION_X ); + positionX = ( v.type( ) == QVariant::Double ? v.toDouble( ) : 0.0 ); + v = model( )->data( index, Qt::UserRole + GraphItemModel::POSITION_Y ); + positionY = ( v.type( ) == QVariant::Double ? v.toDouble( ) : 0.0 ); + + v = model( )->data( index, Qt::UserRole + GraphItemModel::DIMENSION_X ); + dimensionX = ( v.type( ) == QVariant::Double ? v.toDouble( ) : dimensionX ); + v = model( )->data( index, Qt::UserRole + GraphItemModel::DIMENSION_Y ); + dimensionY = ( v.type( ) == QVariant::Double ? v.toDouble( ) : dimensionY ); + + node->setLabel( content ); + node->setPosition( positionX, positionY ); + node->setDimension( dimensionX, dimensionY ); + + // Update node style (if such a style is present) + can::Style* style = _styleManager.getStyle( node ); + if ( style == 0 ) + { + style = new can::Style( "" ); + _styleManager.setStyle( node, *style ); + } + + if ( style != 0 ) + { + v = model( )->data( index, Qt::BackgroundColorRole ); + QColor c = ( v.type( ) == QVariant::Color ? v.value( ) : QColor( ) ); + if ( c.isValid( ) ) + style->addColor( "backcolor", c.red( ), c.green( ), c.blue( ) ); + + v = model( )->data( index, Qt::DecorationRole ); + QIcon i = ( v.type( ) == QVariant::Icon ? v.value( ) : QIcon( ) ); + if ( !i.isNull( ) ) + style->addIcon( "icon", i ); + } + } + update( ); // TODO: update uniquement pour la zone graphique du node +} + +void GraphItemView::reset( ) +{ + QAbstractItemView::reset( ); + + if ( model( ) != 0 ) + { + _graph->generateRootNodes( ); + + // Explore model and map it items to graphical elements + for ( int i = 0; i < model( )->rowCount( ); i++ ) + { + QModelIndex index = model( )->index( i, 0 ); + QModelIndex noItem; + visitModelIndex( *model( ), index, noItem ); + } + + connect( model( ), SIGNAL( rowsInserted(const QModelIndex&,int,int) ), this, SLOT( rowsInserted(const QModelIndex&,int,int) ) ); + connect( model( ), SIGNAL( rowsAboutToBeInserted(const QModelIndex&,int,int) ), this, SLOT( rowsAboutToBeInserted(const QModelIndex&,int,int) ) ); + connect( model( ), SIGNAL( rowsRemoved(const QModelIndex&,int,int) ), this, SLOT( rowsRemoved(const QModelIndex&,int,int) ) ); + connect( model( ), SIGNAL( rowsAboutToBeRemoved(const QModelIndex&,int,int) ), this, SLOT( rowsAboutToBeRemoved(const QModelIndex&,int,int) ) ); + } +} + +void GraphItemView::rowsAboutToBeInserted( const QModelIndex& parent, int start, int end ) +{ +} + +void GraphItemView::rowsInserted( const QModelIndex& parent, int start, int end ) +{ + QModelIndex index( parent ); + QAbstractItemView::rowsInserted( parent, start, end ); + + if ( !parent.isValid( ) ) // Root item + { + for ( int row = start; row < end; row++ ) + { + QModelIndex nodeIndex = model( )->index( row, 0, parent ); + QModelIndex invalidIndex; + visitModelIndex( *model( ), nodeIndex, invalidIndex ); + } + } + else + { + for ( int row = start; row < end; row++ ) + { + QModelIndex nodeIndex = model( )->index( row, 0, parent ); + QModelIndex parentIndex( parent ); + + visitModelIndex( *model( ), nodeIndex, parentIndex ); + } + } +} + +void GraphItemView::rowsAboutToBeRemoved( const QModelIndex & parent, int start, int end ) +{ + //QAbstractItemView::rowsAboutToBeRemoved( parent, start, end ); + for ( int row = start; row < end; row++ ) + { + QModelIndex nodeIndex = model( )->index( row, 0, parent ); + if ( !nodeIndex.isValid( ) ) + continue; + ModelIndexGraphicItemMap::iterator indexIter = _modelIndexGraphicItemMap.find( nodeIndex.internalPointer( ) ); + if ( indexIter != _modelIndexGraphicItemMap.end( ) ) + { + Node* nodeItem = static_cast< Node* >( indexIter->second ); + //getCanvas( )->removeItem( nodeItem ); // FIXME + + la::Node* node = getGraphicItemNode( nodeItem ); + if ( node != 0 ) + { + // Remove arrows + la::Edge::List edges; + std::copy( node->getInEdges( ).begin( ), node->getInEdges( ).end( ), std::back_insert_iterator< la::Edge::List >( edges ) ); + std::copy( node->getOutEdges( ).begin( ), node->getOutEdges( ).end( ), std::back_insert_iterator< la::Edge::List >( edges ) ); + for ( la::Edge::List::iterator edgeIter = edges.begin( ); edgeIter != edges.end( ); edgeIter++ ) + { + EdgeGraphicItemMap::iterator canvasEdgeIter = _edgeGraphicItemMap.find( *edgeIter ); + if ( canvasEdgeIter != _edgeGraphicItemMap.end( ) ) + { + ( canvasEdgeIter->second )->update( 0, 0 ); + _edgeGraphicItemMap.erase( *edgeIter ); + } + } + + _nodeGraphicItemMap.erase( node ); + } + + _modelIndexNodeMap.erase( nodeIndex.internalPointer( ) ); + _modelIndexGraphicItemMap.erase( nodeIndex.internalPointer( ) ); + _graphicItemModelIndexMap.erase( nodeItem ); + delete nodeItem; + } + } +} + +void GraphItemView::rowsRemoved( const QModelIndex& parent, int first, int last ) +{ + +} + +void GraphItemView::dataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight ) +{ + if ( !topLeft.isValid( ) ) + return; + + QModelIndex changedDataIndex( topLeft ); + la::Node* topLeftNode = getModelIndexNode( changedDataIndex ); + if ( topLeftNode != 0 ) + { + can::Node* topLeftItem = static_cast< can::Node* >( getNodeGraphicItem( topLeftNode ) ); + if ( topLeftItem != 0 ) + { + Style* style = _styleManager.getStyle( topLeftNode ); + if ( style == 0 ) + style = _styleManager.getStyle( topLeftNode->getType( ) ); + if ( style != 0 ) + { + //topLeftItem->update( topLeftNode->getLabel( ), *style ); // FIXME + //topLeftItem->updateGeometry( *style ); + } + else + { + can::Style emptyStyle( "empty" ); + //topLeftItem->update( topLeftNode->getLabel( ), emptyStyle ); // FIXME + //topLeftItem->updateGeometry( emptyStyle ); + } + } + } + + update( ); +} +//----------------------------------------------------------------------------- + + + +/* Model Index and Graphic Item Management *///-------------------------------- +la::Node* GraphItemView::getGraphicItemNode( const QGraphicsItem* item ) +{ + if ( item == 0 ) + return 0; + GraphicItemModelIndexMap::const_iterator graphicItemIter = _graphicItemModelIndexMap.find( item ); + if ( graphicItemIter != _graphicItemModelIndexMap.end( ) ) + { + // Return the graph node associed to the model index found + ModelIndexNodeMap::iterator nodeIter = _modelIndexNodeMap.find( ( *graphicItemIter ).second ); + if ( nodeIter != _modelIndexNodeMap.end( ) ) + return nodeIter->second; + } + return 0; +} + +QGraphicsItem* GraphItemView::getNodeGraphicItem( const la::Node* node ) +{ + if ( node == 0 ) + return 0; + NodeGraphicItemMap::const_iterator nodeIter = _nodeGraphicItemMap.find( node ); + if ( nodeIter != _nodeGraphicItemMap.end( ) ) + return ( nodeIter->second )->getGraphicsItem( ); + return 0; +} + +la::Node* GraphItemView::getModelIndexNode( QModelIndex& index ) +{ + if ( !index.isValid( ) ) + return 0; + + ModelIndexNodeMap::iterator modelIndexIter = _modelIndexNodeMap.find( index.internalPointer( ) ); + if ( modelIndexIter != _modelIndexNodeMap.end( ) ) + return modelIndexIter->second; + return 0; +} + +la::Node* GraphItemView::getCurrentNode( QPoint& p ) +{ + /*Item::List collisions; + //getCanvas( )->getCollisions( p, collisions ); // FIXME + if ( collisions.begin( ) != collisions.end( ) ) + { + Item* item = *collisions.begin( ); + //if ( getCanvas( ) != 0 && !getCanvas( )->isFreed( item ) ) // FIXME + // return getGraphicItemNode( item ); + }*/ + return 0; +} +//----------------------------------------------------------------------------- + + + +/* Style Management *///------------------------------------------------------- +void GraphItemView::updateGraphStyles( ) +{ + // Update all items position + // FIXME +/* Item::List& items = _canvas->getItems( ); + Item::List::iterator itemIter = items.begin( ); + for ( ; itemIter != items.end( ); itemIter++ ) + { + Item* item = *itemIter; + + if ( item->getType( ) != Item::NODE ) + continue; + + Node* rectangularItem = static_cast< Node* >( item ); + la::Node* node = getGraphicItemNode( rectangularItem ); + if ( node != 0 ) + { + Style* style = _styleManager.getStyle( node ); + if ( style == 0 ) + style = _styleManager.getStyle( node->getType( ) ); + if ( style != 0 ) + item->updateStyle( *style ); + } + }*/ +} +//----------------------------------------------------------------------------- + + + +/* Layout Management *///------------------------------------------------------ +/*! + \note The ownership of the given layout object is transferred to this view. + \param layout New layout to use with this view (must not be 0). + */ +void GraphItemView::setGraphLayout( la::Layout* layout, utl::Progress& progress ) +{ + if ( layout == 0 ) + return; + + if ( _layout != 0 ) + { + delete _layout; + _layout = 0; + } + _layout = layout; +} + +void GraphItemView::layoutGraph( utl::Progress& progress, la::Layout* layout, int step, la::Node* except ) +{ + if ( _graph == 0 ) + return; + if ( _layout == 0 && layout == 0 ) + return; + + QRectF r = getGraphicsView( )->sceneRect( ); + r.setWidth( std::max( r.width( ), ( double )width( ) ) ); + r.setHeight( std::max( r.height( ), ( double )height( ) ) ); + + if ( layout != 0 ) + layout->layout( *_graph, *getGraphicsView( )->getGrid( ), r, progress, step ); + else if ( _layout != 0 && getGraphicsView( )->getGrid( ) != 0 ) + _layout->layout( *_graph, *getGraphicsView( )->getGrid( ), r, progress, step ); + + // Update all nodes positions + { + NodeGraphicItemMap::iterator nodeIter = _nodeGraphicItemMap.begin( ); + for ( ; nodeIter != _nodeGraphicItemMap.end( ); nodeIter++ ) + { + const la::Node* node = nodeIter->first; + can::AbstractNode* item = nodeIter->second; + if ( node != 0 && item != 0 && node != except ) + item->getGraphicsItem( )->setPos( node->getPosition( )( 0 ), node->getPosition( )( 1 ) ); + } + } + _graphicsView->update( ); + update( ); +} + +la::VectorF GraphItemView::getBoundingBox( const la::Node::List& nodes ) +{ + la::VectorF bbox( 2 ); + bbox( 0 ) = 0; + bbox( 1 ) = 0; + + la::Node::List::const_iterator nodeIter = nodes.begin( ); + for ( ; nodeIter != nodes.end( ); nodeIter++ ) + { + const la::Node* node = *nodeIter; + const la::VectorF& position = node->getPosition( ); + const la::VectorF& dimension = node->getDimension( ); + + if ( position( 0 ) + dimension( 0 ) > bbox( 0 ) ) + bbox( 0 ) = position( 0 ) + dimension( 0 ); + if ( position( 1 ) + dimension( 1 ) > bbox( 1 ) ) + bbox( 1 ) = position( 1 ) + dimension( 1 ); + } + return bbox; +} +//----------------------------------------------------------------------------- + + + +/* ScrollArea Management *///-------------------------------------------------- +void GraphItemView::resizeEvent( QResizeEvent* event ) +{ + int w = width( ); + int h = height( ); + _graphicsView->resize( w, h ); +} + +bool GraphItemView::eventFilter( QObject *o, QEvent *e ) +{ + return false; +} +//----------------------------------------------------------------------------- + + + +/* Graphic Node Factory Management *///---------------------------------------- +/*! Ownership for the factory is transfrerred to this graph item view. + \param factory Graphic node factory that must be used when generating node graphic counterpart. + */ +void GraphItemView::registerGraphicNodeFactory( AbstractNode::AbstractFactory* factory ) +{ + assert( factory != 0 ); + if ( factory->isDefaultFactory( ) ) + _factories.push_back( factory ); // Default factories must be tested after standard ones + else + _factories.push_front( factory ); +} + +/*! + \return A adequat graphic counterpart for node, or a node from a default factory, or 0 if no (default) factories are registered. + */ +AbstractNode* GraphItemView::createGraphicNode( la::Node& node, Style::Manager& styleManager, Style& style, + QGraphicsItem* parent, QGraphicsScene* scene, + QPoint origin, const std::string& label ) +{ + AbstractNode::AbstractFactory::List::iterator factoryIter = _factories.begin( ); + for ( ; factoryIter != _factories.end( ); factoryIter++ ) + { + AbstractNode::AbstractFactory* factory = *factoryIter; + if ( factory->isDefaultFactory( ) ) // Default factories create graphic node whatever the node type is + return factory->create( node, styleManager, style, parent, scene, origin, label ); + + if ( node.getType( ) == factory->getNodeType( ) ) + return factory->create( node, styleManager, style, parent, scene, origin, label ); + } + return 0; // No adequat nor default factory found +} +//----------------------------------------------------------------------------- + + +} // ::qan::can +} // ::qan +//----------------------------------------------------------------------------- + + ============================================================ --- libs/qanava/src/can/canGraphItemView.h 978a8a7cfb5c35da58ec0f0a4b9b9b686809b7e9 +++ libs/qanava/src/can/canGraphItemView.h 978a8a7cfb5c35da58ec0f0a4b9b9b686809b7e9 @@ -0,0 +1,279 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canGraphItemView.h +// \author Benoit Autheman (address@hidden) +// \date 2005 November 22 +//----------------------------------------------------------------------------- + + +#ifndef canGraphItemView_h +#define canGraphItemView_h + + +// Qanava headers +#include "../la/laNode.h" +#include "../la/laGraph.h" +#include "../la/laLayout.h" +#include "./canItemGeom.h" +#include "./canGraphicsView.h" + + +// QT headers +#include +#include +#include +#include +#include +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan + namespace can { // ::qan::can + + class Grid; + + + //! Display a graph provided as a QT Interview based model. + /*! + \nosubgrouping + */ + class GraphItemView : public QAbstractItemView + { + Q_OBJECT + + /*! \name View Construction *///--------------------------------------- + //@{ + public: + + //! GraphItemView constructor with optionnal settings for graph widget initialization. + GraphItemView( QWidget* parent, la::Graph* graph = 0, /*can::Grid* grid = 0,*/ + QColor backColor = QColor( 170, 171, 205 ), QSize size = QSize( 300, 150 ) ); + + //! Clear this item view of all elements and set its model to 0. + void clear( ); + + QGraphicsScene* getGraphicsScene( ) { return _graphicsScene; } + + GraphicsView* getGraphicsView( ) { return _graphicsView; } + + void setGrid( Grid* grid ) { _graphicsView->setGrid( grid ); } + + virtual QSize sizeHint( ) const { return QSize( 300, 250 ); } + + private: + + QGraphicsScene* _graphicsScene; + + GraphicsView* _graphicsView; + + la::Graph* _graph; + //@} + //--------------------------------------------------------------------- + + + + /*! \name QT View Interface Management *///---------------------------- + //@{ + public: + + virtual void setModel ( QAbstractItemModel* model ); + + virtual QModelIndex indexAt( const QPoint& p ) const; + + virtual void scrollTo( const QModelIndex& index, ScrollHint hint = EnsureVisible ) { } + + virtual QRect visualRect( const QModelIndex& index ) const { return QRect( 0, 0, 0, 0 ); } + + virtual int horizontalOffset( ) const { return 0; } + + virtual bool isIndexHidden ( const QModelIndex & index ) const { return false; } + + virtual QModelIndex moveCursor ( CursorAction cursorAction, Qt::KeyboardModifiers modifiers ) { return QModelIndex( ); } + + virtual void setSelection ( const QRect& rect, QItemSelectionModel::SelectionFlags flags ) { } + + virtual int verticalOffset( ) const { return 0; } + + virtual QRegion visualRegionForSelection ( const QItemSelection& selection ) const { return QRegion( 0, 0, 0, 0 ); } + + protected: + + //! Visit a model index and its child index, and map encoutered indexes. + void visitModelIndex( QAbstractItemModel& model, QModelIndex& modelIndex, QModelIndex& parentIndex ); + + //! Map a given model index to a graph node and a canvas geometric items. + void mapIndex( QModelIndex& index, QModelIndex& parent ); + + //! Update an index associed graphic item (and eventually node) with the current index data. + void updateModelIndexGraphicItem( QModelIndex& index ); + + //! Update a node from data comming from its associed model index (assuming the model data are more accurate than the node ones). + void updateModelIndexNode( QModelIndex& index, la::Node* node = 0 ); + + protected slots: + + virtual void reset( ); + + protected slots: + + virtual void rowsAboutToBeInserted( const QModelIndex& parent, int start, int end ); + + virtual void rowsInserted( const QModelIndex& parent, int start, int end ); + + virtual void rowsAboutToBeRemoved( const QModelIndex & parent, int start, int end ); + + virtual void rowsRemoved( const QModelIndex &parent, int first, int last ); + + virtual void dataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight ); + //@} + //--------------------------------------------------------------------- + + + + /*! \name Model Index and Graphic Item Management *///----------------- + //@{ + public: + + //! Get a graph node associed to a given graphic item. + la::Node* getGraphicItemNode( const QGraphicsItem* item ); + + //! Get a graphic item associed to a given graph node. + QGraphicsItem* getNodeGraphicItem( const la::Node* node ); + + //! Get a graph node associed to a given model item index. + la::Node* getModelIndexNode( QModelIndex& index ); + + //! Get the node that is currently under the mouse pointer. + la::Node* getCurrentNode( QPoint& p ); + + protected: + + typedef std::map< void*, la::Node* > ModelIndexNodeMap; + + typedef std::map< void*, can::AbstractNode* > ModelIndexGraphicItemMap; + + typedef std::map< const la::Edge*, can::Edge* > EdgeGraphicItemMap; + + typedef std::map< const la::Node*, can::AbstractNode* > NodeGraphicItemMap; + + typedef std::map< const QGraphicsItem*, void* > GraphicItemModelIndexMap; + + ModelIndexNodeMap _modelIndexNodeMap; + + ModelIndexGraphicItemMap _modelIndexGraphicItemMap; + + EdgeGraphicItemMap _edgeGraphicItemMap; + + NodeGraphicItemMap _nodeGraphicItemMap; + + GraphicItemModelIndexMap _graphicItemModelIndexMap; + //@} + //--------------------------------------------------------------------- + + + + /*! \name Style Management *///---------------------------------------- + //@{ + public: + + //! Get the graph view style manager. + Style::Manager& getStyleManager( ) { return _styleManager; } + + //! Update nodes view to refect the current state of styles in the model graph. + void updateGraphStyles( ); + + protected: + + //! Graph view style manager. + Style::Manager _styleManager; + //@} + //--------------------------------------------------------------------- + + + + /*! \name Layout Management *///--------------------------------------- + //@{ + public: + + //! . + void setGraphLayout( la::Layout* layout, utl::Progress& progress ); + + //! . + la::Layout* getGraphLayout( la::Layout& layout ) { return _layout; } + + //! . + const la::Layout* getGraphLayout( la::Layout& layout ) const { return _layout; } + + //! . + void layoutGraph( utl::Progress& progress, la::Layout* layout = 0, int step = -1, la::Node* except = 0 ); + + //! Get bounding box for a group of nodes. + static la::VectorF getBoundingBox( const la::Node::List& nodes ); + + protected: + + //! . + la::Layout* _layout; + //@} + //--------------------------------------------------------------------- + + + + /*! \name ScrollArea Management *///----------------------------------- + //@{ + protected: + + void resizeEvent( QResizeEvent* event ); + + bool eventFilter( QObject* o, QEvent* e ); + //@} + //--------------------------------------------------------------------- + + + + /*! \name Graphic Node Factory Management *///------------------------- + //@{ + public: + + //! Register a graphic node factory for a certain type of nodes (from graph topology to graph graphic visualization). + void registerGraphicNodeFactory( AbstractNode::AbstractFactory* factory ); + + //! Create a graphic node from a topological node using the currently registered graphic node factories. + AbstractNode* createGraphicNode( la::Node& node, Style::Manager& styleManager, Style& style, + QGraphicsItem* parent, QGraphicsScene* scene, + QPoint origin, const std::string& label ); + + private: + + AbstractNode::AbstractFactory::List _factories; + //@} + //--------------------------------------------------------------------- + }; +} // ::qan::can +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // canGraphItemView_h + ============================================================ --- libs/qanava/src/can/canGraphicsView.cpp 7939221fdb922f5b8cd345081892f970cce3a331 +++ libs/qanava/src/can/canGraphicsView.cpp 7939221fdb922f5b8cd345081892f970cce3a331 @@ -0,0 +1,210 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canGraphicsView.cpp +// \author Benoit Autheman (address@hidden) +// \date 2006 July 29 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "./canGraphicsView.h" +#include "./canGrid.h" + + +// QT headers +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan +namespace can { // ::qan::can + + + +/* GraphicsView Constructors/Destructors *///---------------------------------- +GraphicsView::GraphicsView( QWidget* parent ) : + QGraphicsView( parent ), + _grid( 0 ), + _controllerManager( this ), + _zoom( 1.0 ), + _zoomMaxFactor( 2 ) +{ + setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); + setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); + setAlignment( Qt::AlignLeft | Qt::AlignTop ); + + getControllerManager( ).registerController( new PanController( *this ) ); + getControllerManager( ).registerController( new ZoomWindowController( *this ) ); + getControllerManager( ).registerController( new ZoomController( *this ) ); + + setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + + setCacheMode( QGraphicsView::CacheBackground ); +} + +GraphicsView::GraphicsView( QGraphicsScene* scene, QWidget* parent ) : + QGraphicsView( scene, parent ), + _grid( 0 ), + _controllerManager( this ), + _zoom( 1.0 ), + _zoomMaxFactor( 2 ) +{ + setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); + setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); + setAlignment( Qt::AlignLeft | Qt::AlignTop ); + + getControllerManager( ).registerController( new PanController( *this ) ); + getControllerManager( ).registerController( new ZoomWindowController( *this ) ); + getControllerManager( ).registerController( new ZoomController( *this ) ); + + setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + + setCacheMode( QGraphicsView::CacheBackground ); + if ( scene != 0 ) + scene->setItemIndexMethod( QGraphicsScene::NoIndex ); +} +//----------------------------------------------------------------------------- + + + +/* Grid Management *///-------------------------------------------------------- +void GraphicsView::drawBackground( QPainter* painter, const QRectF& rect ) +{ + if ( _grid != 0 ) + _grid->drawBackground( *painter, rect ); +} +//----------------------------------------------------------------------------- + + + +/* View Controller Management *///----------------------------------------------- +void GraphicsView::keyPressEvent( QKeyEvent* e ) +{ + QGraphicsView::keyPressEvent( e ); + + if ( _controllerManager.keyPressEvent( e ) ) + viewport( )->update( ); +} + +void GraphicsView::mousePressEvent( QMouseEvent* e ) +{ + QGraphicsView::mousePressEvent( e ); + + if ( _controllerManager.mousePressEvent( e ) ) + viewport( )->update( ); +} + +void GraphicsView::mouseReleaseEvent( QMouseEvent* e ) +{ + QGraphicsView::mouseReleaseEvent( e ); + + if ( _controllerManager.mouseReleaseEvent( e ) ) + viewport( )->update( ); +} + +void GraphicsView::mouseMoveEvent( QMouseEvent* e ) +{ + QGraphicsView::mouseMoveEvent( e ); + + if ( _controllerManager.mouseMoveEvent( e ) ) + viewport( )->update( ); +} + +void GraphicsView::mouseDoubleClickEvent( QMouseEvent* e ) +{ + QGraphicsView::mouseDoubleClickEvent( e ); + + if ( _controllerManager.mouseDoubleClickEvent( e ) ) + viewport( )->update( ); +} + +void GraphicsView::wheelEvent( QWheelEvent* e ) +{ + QGraphicsView::wheelEvent( e ); + + if ( _controllerManager.wheelEvent( e ) ) + viewport( )->update( ); +} + +QAction* GraphicsView::getAction( QString name ) +{ + Controller* controller = _controllerManager.getController( name ); + if ( controller != 0 ) + return controller->getAction( ); + + Controller::Manager::iterator controllerIter = _controllerManager.begin( ); + for ( ; controllerIter != _controllerManager.end( ); controllerIter++ ) + { + QAction* action = ( *controllerIter )->getAction( name ); // Create an action by name + if ( action != 0 ) + return action; + } + return 0; +} +//----------------------------------------------------------------------------- + + + +/* Zoom Management *///------------------------------------------------------- +void GraphicsView::setZoom( double zoom ) +{ + qreal factor = matrix( ).scale( zoom, zoom ).mapRect( QRectF( 0., 0., 1., 1.) ).width( ); + if ( factor < 0.07 || factor > 100 ) + return; + + if ( zoom > 0.7 ) + { + _zoom = zoom; + QMatrix m; + m.scale( zoom, zoom ); + setMatrix( m ); + } +} + +/*! + With a maximum zoom factor of 2 (this default value can be changed with setZoomMaxFactor() method), a + one factor zoom (ie a normal view) is obtained by setting the zoom to 50% (half of the maximum magnification + factor). + + \param value Zoom value in percent between (almost) 0 and the max zoom magnification (must be 0_1 to 100). + */ +void GraphicsView::setZoomPercent( int value ) +{ + double zoomPercent = value; + if ( zoomPercent == 0 ) + zoomPercent = 1; + if ( zoomPercent > 100 ) + zoomPercent = 100; + + // Set zoom factor + double zoomMaxFactor = ( _zoomMaxFactor < 0.1 ? 0.1 : _zoomMaxFactor ); + setZoom( zoomPercent / 100.f * zoomMaxFactor ); +} +//----------------------------------------------------------------------------- + + +} // ::qan::can +} // ::qan +//----------------------------------------------------------------------------- + + ============================================================ --- libs/qanava/src/can/canGraphicsView.h d507ca7454e22edc14aa0ad3bfccb5721110b9c1 +++ libs/qanava/src/can/canGraphicsView.h d507ca7454e22edc14aa0ad3bfccb5721110b9c1 @@ -0,0 +1,151 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canGraphicsView.h +// \author Benoit Autheman (address@hidden) +// \date 2006 July 29 +//----------------------------------------------------------------------------- + + +#ifndef canGraphicsView_h +#define canGraphicsView_h + + +// Qanava headers +#include "./canController.h" + + +// QT headers +#include +#include +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan + //! Classes related to concrete graph drawing in a QT graphics view. + namespace can { // ::qan::can + + class Grid; + + class GraphicsView : public QGraphicsView + { + Q_OBJECT + + /*! \name GraphicsView Constructors/Destructors *///------------------- + //@{ + public: + + GraphicsView( QWidget* parent = 0 ); + + GraphicsView( QGraphicsScene* scene, QWidget* parent = 0 ); + + virtual QSize sizeHint( ) const { return QSize( 300, 250 ); } + //@} + //--------------------------------------------------------------------- + + + + /*! \name Grid Management *///----------------------------------------- + //@{ + public: + + void setGrid( can::Grid* grid ) { _grid = grid; } + + can::Grid* getGrid( ) { return _grid; } + + protected: + + virtual void drawBackground( QPainter* painter, const QRectF& rect ); + + private: + + can::Grid* _grid; + //@} + //--------------------------------------------------------------------- + + + + /*! \name View Controllers Management *///----------------------------- + //@{ + protected: + + virtual void keyPressEvent( QKeyEvent* e ); + + virtual void mousePressEvent( QMouseEvent* e ); + + virtual void mouseReleaseEvent( QMouseEvent* e ); + + virtual void mouseMoveEvent( QMouseEvent* e ); + + virtual void mouseDoubleClickEvent( QMouseEvent* e ); + + virtual void wheelEvent( QWheelEvent* e ); + + public: + + //! Get this item view controller manager. + Controller::Manager& getControllerManager( ) { return _controllerManager; } + + //! Get the action for a controller with a given name. + QAction* getAction( QString name ); + + private: + + Controller::Manager _controllerManager; + //@} + //--------------------------------------------------------------------- + + + + /*! \name Zoom Management *///---------------------------------------- + //@{ + public: + + //! Set the maximum zoom factor that can be sets with the setZoomValue() method. + void setZoomMaxFactor( double zoomMaxFactor ) { _zoomMaxFactor = zoomMaxFactor; } + + double getZoom( ) const { return _zoom; } + + void setZoom( double zoom ); + + public slots: + + //! Set the current zoom factor value in percents (from 1 to 100, 100 sets the maximum zoom factor). + void setZoomPercent( int value ); + + private: + + double _zoom; + + //! Maximum zoom factor (default = 2). + double _zoomMaxFactor; + //@} + //--------------------------------------------------------------------- + }; +} // ::qan::can +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // canGraphicsView_h + ============================================================ --- libs/qanava/src/can/canGrid.cpp 2e8ad9f3cd734e63856b1c8a7ff8675ae42d5eec +++ libs/qanava/src/can/canGrid.cpp 2e8ad9f3cd734e63856b1c8a7ff8675ae42d5eec @@ -0,0 +1,157 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canGrid.cpp +// \author Benoit Autheman (address@hidden) +// \date 2004 December 05 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "canGrid.h" + + +// QT headers +#include +#include +#include + + +// STD headers +#include + + +namespace qan { // ::qan +namespace can { // ::qan::can + + + +/* Grid Constructor/Destructor *///------------------------------------------- +/*! + */ +Grid::Grid( GraphicsView* graphicsView ) : + QGraphicsItem( 0, graphicsView->scene( ) ) +{ + //connect( graphView->getGraphicsScene( ), SIGNAL( sceneRectChanged(const QRectF&) ), + // this, SLOT( sceneRectChanged(const QRectF&) ) ); + + graphicsView->setGrid( this ); +} + +Grid::~Grid( ) +{ + +} +//----------------------------------------------------------------------------- + + +/* Graphics View Grid Implementation *///-------------------------------------- +QRectF Grid::boundingRect( ) const +{ + return QRectF( QPointF( 0., 0. ), QSizeF( 1., 1. ) ); +} + +void Grid::drawBackground( QPainter& painter, const QRectF& rect ) +{ + +} +//----------------------------------------------------------------------------- + + + +/* Grid Content Management *///----------------------------------------------- +void Grid::addLine( QLineF l, float w, bool dash, bool dot ) +{ + QGraphicsLineItem* line = new QGraphicsLineItem( l, this, scene( ) ); + + // TODO: dash, dot, w +} + +void Grid::addRectangle( QRectF r, QColor c ) +{ +} + +void Grid::addText( const std::string& text, QPointF p, bool bold ) +{ +} + +void Grid::addHorizontalLine( QLineF l, int w, bool dash, bool dot ) +{ +} + +void Grid::addVerticalLine( QLineF l, int w, bool dash, bool dot ) +{ +} +//----------------------------------------------------------------------------- + + + +/* Regular Grid Management *///----------------------------------------------- +GridRegular::GridRegular( GraphicsView* graphicsView, int spacing ) : + Grid( graphicsView ), + _spacing( spacing ), + _sizeMax( 0, 0 ), + _gradCount( 0, 0 ) +{ + +} +//----------------------------------------------------------------------------- + + + +/* CheckBoard Grid Management *///-------------------------------------------- +GridCheckBoard::GridCheckBoard( GraphicsView* graphicsView, QColor white, QColor black, qreal length ) : + Grid( graphicsView ), + _white( white ), + _black( black ) +{ + _squaresPattern = QPixmap( length * 2, length * 2 ); + QPainter painter( &_squaresPattern ); + painter.fillRect( 0, 0, length, length, white ); + painter.fillRect( length, 0, length, length, black ); + painter.fillRect( 0, length, length, length, black ); + painter.fillRect( length, length, length, length, white ); + painter.end( ); +} + +void GridCheckBoard::drawBackground( QPainter& painter, const QRectF& rect ) +{ + Grid::drawBackground( painter, rect ); + + int left = ( int )rect.left( ); + int top = ( int )rect.top( ); + int x = ( ( left / 100 ) * 100 ); + int y = ( ( top / 100 ) * 100 ); + + if ( left < 0 ) + x = x - 100; + if ( top < 0 ) + y = y - 100; + + if ( !_squaresPattern.isNull( ) ) + painter.drawTiledPixmap( x, y, rect.width( ) + 100, rect.height( ) + 100, _squaresPattern ); +} +//----------------------------------------------------------------------------- + + +} // ::qan::can +} // ::qan ============================================================ --- libs/qanava/src/can/canGrid.h 4644ad4dfd030e2e00d101f7c5ed425c51a2c25e +++ libs/qanava/src/can/canGrid.h 4644ad4dfd030e2e00d101f7c5ed425c51a2c25e @@ -0,0 +1,179 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canGrid.h +// \author Benoit Autheman (address@hidden) +// \date 2004 December 05 +//----------------------------------------------------------------------------- + + +#ifndef canGrid_h +#define canGrid_h + + +// Qanava headers +#include "../la/laGrid.h" +#include "./canItemGeom.h" +#include "./canGraphicsView.h" + + +// QT headers +#include +#include + + +// STL headers +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan +namespace can { // ::qan::can + + class Canvas; + + + //! Implements the abstract methods defined in class la::Grid. + /*! + \nosubgrouping + */ + class Grid : public QObject, public QGraphicsItem, public la::Grid + { + Q_OBJECT + + /*! \name Grid Constructor/Destructor *///---------------------------- + //@{ + public: + + //! Grid constructor with canvas and backcolor initialization (backcolor is not drawn, except for optimized line's backcolor). + Grid( GraphicsView* graphicsView ); + + //! Grid destructor, once destroyed, all graphic items are cleared from the grid canvas. + virtual ~Grid( ); + //@} + //--------------------------------------------------------------------- + + + + /*! \name Graphics View Grid Implementation *///----------------------- + //@{ + public: + + QRectF boundingRect( ) const; + + virtual void paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0 ) { } + + virtual void drawBackground( QPainter& painter, const QRectF& rect ); + //@} + //--------------------------------------------------------------------- + + + + /*! \name Grid Construction Management *///--------------------------- + //@{ + public: + + //! \copydoc la::Grid::addLine() + virtual void addLine( QLineF l, float w = 1, bool dash = false, bool dot = false ); + + //! \copydoc la::Grid::addRectangle() + virtual void addRectangle( QRectF r, QColor c ); + + //! \copydoc la::Grid::addText() + virtual void addText( const std::string& text, QPointF p, bool bold = false ); + + //! \copydoc la::Grid::addHorizontalLine() + virtual void addHorizontalLine( QLineF l, int w = 1, bool dash = false, bool dot = false ); + + //! \copydoc la::Grid::addVerticalLine() + virtual void addVerticalLine( QLineF l, int w = 1, bool dash = false, bool dot = false ); + //@} + //--------------------------------------------------------------------- + }; + + + + //! Regular grid draws a square pattern of horizontal and vertical dotted lines (ie a standard grid!). + /*! + Qanava regular grid + + \nosubgrouping + */ + class GridRegular : public can::Grid + { + /*! \name Regular Grid Management *///-------------------------------- + //@{ + public: + + //! GridRegular constructor with grid line spacing initialization. + GridRegular( GraphicsView* graphicsView, int spacing = 60 ); + + virtual ~GridRegular( ) { } + + private: + + int _spacing; + + QSize _sizeMax; + + QPoint _gradCount; + //@} + //--------------------------------------------------------------------- + }; + + + //! Draw a bicolor checkboard pattern regular grid. + /*! + \nosubgrouping + */ + class GridCheckBoard : public can::Grid + { + Q_OBJECT + + /*! \name CheckBoard Grid Management *///----------------------------- + //@{ + public: + + //! GridCheckBoard constructor with black, white color and square size initialization. + GridCheckBoard( GraphicsView* graphicsView, QColor white, QColor black, qreal length = 50. ); + + virtual ~GridCheckBoard( ) { } + + virtual void drawBackground( QPainter& painter, const QRectF& rect ); + + private: + + QPixmap _squaresPattern; + + QColor _white; + + QColor _black; + //@} + //--------------------------------------------------------------------- + }; +} // ::qan::can +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // canGrid_h + ============================================================ --- libs/qanava/src/can/canItemGeom.cpp a7fd96e347cf762c95252ab333a1fad3947f5599 +++ libs/qanava/src/can/canItemGeom.cpp a7fd96e347cf762c95252ab333a1fad3947f5599 @@ -0,0 +1,452 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canItemGeom.cpp +// \author Benoit Autheman (address@hidden) +// \date 2004 October 13 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "./canItemGeom.h" + + +// QT headers +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// STD headers +#include +#include + + +using namespace qan; +using namespace qan::can; + + +/* Arrow Constructor/Destructor *///------------------------------------------- +Edge::Edge( QGraphicsItem* parent, QGraphicsScene* scene, can::Node* src, can::Node* dst ) : + QGraphicsItem( parent, scene ), + _src( src ), + _dst( dst ), + _hasArrow( true ) +{ + setZValue( 0.75 ); + + if ( src != 0 ) + src->addEdge( this ); + if ( dst != 0 ) + dst->addEdge( this ); +} + +Edge::~Edge( ) +{ + +} + +QRectF Edge::boundingRect( ) const +{ + if ( _src == 0 || _dst == 0 ) + return QRectF( ); + + QPointF src = _src->mapToScene( _src->boundingRect( ).center( ) ); + QPointF dst = _dst->mapToScene( _dst->boundingRect( ).center( ) ); + + QPointF topLeft( std::min( src.x( ), dst.x( ) ), // tl=(minx, miny) + std::min( src.y( ), dst.y( ) ) ); + QPointF bottomRight( std::max( src.x( ), dst.x( ) ), // br=(maxx, maxy) + std::max( src.y( ), dst.y( ) ) ); + + return QRectF( 0., 0., bottomRight.x( ) - topLeft.x( ), bottomRight.y( ) - topLeft.y( ) ); +} + +void Edge::update( can::Node* src, can::Node* dst ) +{ + _src = src; + _dst = dst; + + if ( _src == 0 || _dst == 0 ) + return; + + QPointF srcF = _src->mapToScene( _src->boundingRect( ).center( ) ); + QPointF dstF = _dst->mapToScene( _dst->boundingRect( ).center( ) ); + QPointF topLeft( std::min( srcF.x( ), dstF.x( ) ), // tl=(minx, miny) + std::min( srcF.y( ), dstF.y( ) ) ); + + setPos( topLeft ); // setPos should have been called update on the old garbage area ? + + //QGraphicsItem::update( ); + scene( )->update( ); +} + +void Edge::paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget ) +{ + if ( _src == 0 || _dst == 0 ) + return; + + QPointF srcF = _src->mapToScene( _src->boundingRect( ).center( ) ); + QPointF dstF = _dst->mapToScene( _dst->boundingRect( ).center( ) ); + QLineF line( mapFromScene( srcF ), mapFromScene( dstF ) ); + + painter->setPen( QPen( Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin ) ); + painter->drawLine( line ); + + // Draw the arrows if there's enough room + if ( _hasArrow ) + { + const double Pi = 3.141592653; + double TwoPi = 2.0 * Pi; + double angle = ::acos(line.dx() / line.length()); + if (line.dy() >= 0) + angle = TwoPi - angle; + + // Get the intersection between arrow and dst node + QRectF br = mapFromItem( _dst, _dst->boundingRect( ) ).boundingRect( ); + + // Test intersection with all borders + QLineF top( br.topLeft( ), br.topRight( ) ); + QLineF right( br.topRight( ), br.bottomRight( ) ); + QLineF bottom( br.bottomLeft( ), br.bottomRight( ) ); + QLineF left( br.topLeft( ), br.bottomLeft( ) ); + + QPointF i; + if ( line.intersect( top, &i ) == QLineF::BoundedIntersection || + line.intersect( right, &i ) == QLineF::BoundedIntersection || + line.intersect( bottom, &i ) == QLineF::BoundedIntersection || + line.intersect( left, &i ) == QLineF::BoundedIntersection ) + { + painter->setRenderHint( QPainter::Antialiasing ); + painter->setPen( QPen( Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin ) ); + painter->setBrush( QBrush( QColor( 0, 0, 0 ) ) ); + + double angle = ::acos( line.dx( ) / line.length( ) ); + if ( line.dy( ) <= 0 ) + angle = TwoPi - angle; + painter->save( ); + painter->translate( i ); + painter->rotate( angle * 180. / Pi ); + + double arrowSize = 4.; + double arrowLength = 8.; + i = QPointF( -arrowLength - 1., 0. ); + QPolygonF poly; + poly << QPointF( i.x( ), i.y( ) - arrowSize ) + << QPointF( i.x( ) + arrowLength, i.y( ) ) + << QPointF( i.x( ), i.y( ) + arrowSize ) << QPointF( i.x( ), i.y( ) - arrowSize ); + painter->drawPolygon( poly ); + painter->restore( ); + } + } +} + + +/* Node Constructor/Destructor *///-------------------------------------------- +/*! + The following style options are supported: +
    +
  • 'backcolor': Background color, when there is no background image defined. +
  • 'bordercolor': Color of the item border. +
  • 'backimage': Background image (scaled to fit the item size). +
  • 'maximumwidth': Maximum width of the item, content is cropped to fit this with limit. +
  • 'maximumheight': Maximum height of the item, content is cropped to fit this height limit. +
  • 'fontsize': Base size for the font used to display the item label. +
  • 'icon': Display an icon centered in the left of the item. +
  • 'hasshadow': Set this value to false to supress the node shadow. +
+ + An item with an empty style is transparent with no background nor border. + + \param origin Uper left corner of the rectangular item. + \param label Text label to be displayed in the node text area (can be multi line HTML tagged text). + \param style Advanced style to pass optionnal display parameters. + */ +Node::Node( la::Node& node, Style::Manager& styleManager, Style& style, + QGraphicsItem* parent, QGraphicsScene* scene, + QPoint origin, const std::string& label ) : + AbstractNode( node, styleManager, &style ), + QGraphicsRectItem( parent, scene ), + _dimension( 170.0, 45.0 ), + _label( label ), + _shadowColor( ), + _shadowOffset( 1.0 ), + _labelDocument( 0 ), + _labelLayout( 0 ) +{ + setRect( origin.x( ), origin.y( ), _dimension.x( ), _dimension.y( ) ); + setFlag( QGraphicsItem::ItemIsMovable ); + setZValue( 1.0 ); + + updateNode( ); +} + +Node::~Node( ) +{ + +} + +QRectF Node::boundingRect( ) const +{ + if ( hasShadow( ) ) + { + QRectF r = QGraphicsRectItem::boundingRect( ); + r.adjust( 0., 0., _shadowOffset, _shadowOffset ); + return r; + } + else + return QGraphicsRectItem::boundingRect( ); +} + +void Node::paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget ) +{ + if ( hasShadow( ) ) // Draw shadow + { + QBrush b; + b.setStyle( Qt::SolidPattern ); + b.setColor( _shadowColor ); + painter->setBrush( b ); + + QPen p( _shadowColor ); + painter->setPen( p ); + + QRectF r = boundingRect( ); // BR already contain shadow, just modify top left corner + r.setTopLeft( r.topLeft( ) + QPointF( _shadowOffset, _shadowOffset ) ); + painter->drawRect( r ); + } + + // Draw background pixmap + if ( !_backPixmap.isNull( ) ) + { + QBrush b = brush( ); + b.setStyle( Qt::NoBrush ); + setBrush( b ); // Remove default backcolor (usefulle if we have an alpha channel) + + QRectF backRect = boundingRect( ); + backRect.setRight( backRect.right( ) - _shadowOffset ); + backRect.setBottom( backRect.bottom( ) - _shadowOffset ); + backRect.adjust( 0., 0., 1., 1. ); + QRectF srcRect( 0., 0., _backPixmap.width( ), _backPixmap.height( ) ); + painter->drawPixmap( backRect, _backPixmap, srcRect ); + } + + QGraphicsRectItem::paint( painter, option, widget ); + + if ( _labelDocument != 0 && _labelLayout != 0 ) + { + painter->setPen( QColor( 0, 0, 0 ) ); + double textMarginX = 2; + double textMarginY = 0; + double textX = textMarginX; + if ( !_icon.isNull( ) ) // Draw the text right of the icon + textX += _icon.width( ); + double textY = textMarginY; + + QRectF clipRect( textX, textY, _dimension.x( ) - textMarginX, _dimension.y( ) - textMarginY ); + if ( _labelLayout != 0 ) + _labelLayout->draw( painter, QPointF( textX, textY ), + QVector< QTextLayout::FormatRange >( ), clipRect ); + } + + // Draw the item icon centered vertically + if ( !_icon.isNull( ) ) + { + double iconY = 1.; + if ( _dimension.y( ) > _icon.height( ) ) + iconY += ( _dimension.y( ) - _icon.height( ) ) / 2.; + double iconX = 1.; + painter->drawPixmap( ( int )iconX, ( int )iconY, _icon ); + } +} + +void Node::updateNode( ) +{ + if ( getStyle( ) == 0 ) + return; + + QColor backColor = QColor( 255, 255, 255 ); + + if ( !getStyle( )->has( "nobackground" ) ) + { + QBrush b = brush( ); + b.setStyle( Qt::NoBrush ); + setBrush( b ); + } + + if ( getStyle( )->has( "backcolor" ) ) + { + backColor = getStyle( )->getColor( "backcolor" ); + QBrush b = brush( ); + b.setStyle( Qt::SolidPattern ); + b.setColor( backColor ); + setBrush( b ); + } + else + setBrush( QColor( 255, 255, 255 ) ); + + QColor borderColor = QColor( 0, 0, 0 ); + if ( getStyle( )->has( "bordercolor" ) ) + { + borderColor = getStyle( )->getColor( "bordercolor" ); + setPen( borderColor ); + } + + if ( getStyle( )->has( "hasshadow" ) && getStyle( )->getT< bool >( "hasshadow" ) ) + { + if ( getStyle( )->has( "shadowcolor" ) ) + _shadowColor = getStyle( )->getColor( "shadowcolor" ); + else + _shadowColor = QColor( 105, 105, 105 ); + if ( getStyle( )->has( "shadowoffset" ) ) + _shadowOffset = getStyle( )->getT< int >( "shadowoffset" ); + else + _shadowOffset = 5; + } + else + _shadowColor = QColor( ); // Invalid color since there is no shadow + + // Compute the _label size once it is laid out as rich text html + if ( _label.size( ) > 0 ) + { + QFont font; + if ( getStyle( )->has( "fontsize" ) ) + { + int fontSize = getStyle( )->getT< int >( "fontsize" ); + font.setPointSize( fontSize > 0 ? fontSize : 11 ); + } + QString content( _label.c_str( ) ); + _labelDocument = new QTextDocument( 0 ); + _labelDocument->setHtml( content ); + _labelDocument->setDefaultFont( font ); // Necessary to avoid crash in qt4.1.0 + if ( !_labelDocument->isEmpty( ) ) + { + QTextBlock textBlock = _labelDocument->begin( ); + if ( textBlock.isValid( ) ) + { + _labelLayout = textBlock.layout( ); + if ( _labelLayout != 0 ) + { + _labelLayout->beginLayout( ); + + int maximumWidth = 400; + if ( getStyle( )->has( "maximumwidth" ) ) + maximumWidth = getStyle( )->getT< int >( "maximumwidth" ); + + int lineX = 0; + int lineY = 1; + QTextLine line = _labelLayout->createLine( ); + while ( line.isValid( ) ) + { + line.setLineWidth( maximumWidth ); + int naturalWidth = ( int )line.naturalTextWidth( ); + if ( naturalWidth < maximumWidth ) + line.setLineWidth( naturalWidth + 2 ); + + line.setPosition( QPoint( lineX, lineY ) ); + lineY += ( int )line.height( ); + line = _labelLayout->createLine( ); + } + _labelLayout->endLayout( ); + } + } + } + } + + + // Updating node geometry and content + { + // Check for item maximum dimension (if specified) + double maximumWidth = -1.; + double maximumHeight = -1.; + if ( getStyle( )->has( "maximumwidth" ) ) + maximumWidth = getStyle( )->getT< int >( "maximumwidth" ); + if ( getStyle( )->has( "maximumheight" ) ) + maximumHeight = getStyle( )->getT< int >( "maximumheight" ); + + // Compute the item height according to the _label size once formatted and displayed + if ( _labelDocument != 0 && _labelLayout != 0 ) + { + // Do not resize the item larger than its maximum allowed size + double textLayoutWidth = _labelLayout->boundingRect( ).width( ) + 2.; + double textLayoutHeight = _labelLayout->boundingRect( ).height( ) + 2.; + _dimension.setX( maximumWidth > 0. ? std::min( textLayoutWidth, maximumWidth ) : textLayoutWidth ); + _dimension.setY( maximumHeight > 0. ? std::min( textLayoutHeight, maximumHeight ) : textLayoutHeight ); + } + + // Resize the whole item to fit (eventual) icon size + if ( getStyle( )->has( "icon" ) ) + { + QImage icon = getStyleManager( ).getImage( getStyle( )->getImageName( "icon" ) ); + if ( !icon.isNull( ) ) + _icon = QPixmap::fromImage( icon, Qt::OrderedAlphaDither ); + } + + if ( !_icon.isNull( ) ) + { + double w = _dimension.x( ) + _icon.width( ) + 1.; + _dimension.setX( maximumWidth != -1 ? std::min( w, maximumWidth ) : w ); + + double h = std::max( _icon.height( ) + 1., _dimension.y( ) ); + _dimension.setY( maximumHeight != -1 ? std::min( h, maximumHeight ) : h ); + } + + // Update the background image + if ( getStyle( )->has( "backimage" ) ) + { + QImage backImage = getStyleManager( ).getImage( getStyle( )->getImageName( "backimage" ) ); + if ( !backImage.isNull( ) ) + { + QImage image = backImage.scaled( ( int )_dimension.x( ) - 1, ( int )_dimension.y( ) - 1 ); // -1 for the border + if ( !image.isNull( ) ) + _backPixmap = QPixmap::fromImage( image, Qt::OrderedAlphaDither ); + } + } + + // Set item geometry + //setRect( x( ), y( ), _dimension.x( ), _dimension.y( ) ); + setRect( 0., 0., _dimension.x( ), _dimension.y( ) ); + } +} + +QVariant Node::itemChange( GraphicsItemChange change, const QVariant& value ) +{ + if ( change == ItemPositionChange ) + { + updateEdges( ); + } + return QGraphicsItem::itemChange( change, value ); +} +//----------------------------------------------------------------------------- + + + ============================================================ --- libs/qanava/src/can/canItemGeom.h d086d24b922634654241adc27d2126f0ab21b6fa +++ libs/qanava/src/can/canItemGeom.h d086d24b922634654241adc27d2126f0ab21b6fa @@ -0,0 +1,270 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canItemGeom.h +// \author Benoit Autheman (address@hidden) +// \date 2004 October 13 +//----------------------------------------------------------------------------- + + +#ifndef canItemGeom_h +#define canItemGeom_h + + +// Qanava headers +#include "../la/laNode.h" +#include "./canStyle.h" +#include + + +// QT headers +#include +#include +#include +#include +#include +#include +#include +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan +namespace can { // ::qan::can + +class Node; + + class Edge : public QGraphicsItem + { + public: + + Edge( QGraphicsItem* parent, QGraphicsScene* scene, + can::Node* src, can::Node* dst ); + + virtual ~Edge( ); + + QRectF boundingRect( ) const; + + void paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0 ); + + virtual void update( can::Node* src, can::Node* dst ); + + can::Node* getSrc( ) { return _src; } + + can::Node* getDst( ) { return _dst; } + + private: + + can::Node* _src; + + can::Node* _dst; + + QPointF _sourcePoint; + + QPointF _destinationPoint; + + bool _hasArrow; + }; + + + class AbstractNode : public QObject + { + Q_OBJECT + + public: + + AbstractNode( la::Node& node, Style::Manager& styleManager, Style* style ) : + _node( node ), + _styleManager( styleManager ), + _style( style ) + { + if ( style != 0 ) + connect( style, SIGNAL( modified() ), this, SLOT( updateNode() ) ); + } + + virtual ~AbstractNode( ) + { + foreach ( Edge* edge, _edges ) + edge->update( 0, 0 ); + } + + //! Usually, return this casted to a QGraphicsItem. + virtual QGraphicsItem* getGraphicsItem( ) = 0; + + public slots: + + virtual void updateNode( ) = 0; + + protected: + + la::Node& getNode( ) { return _node; } + + Style::Manager& getStyleManager( ) { return _styleManager; } + + Style* getStyle( ) { return _style; } + + private: + + la::Node& _node; + + Style::Manager& _styleManager; + + Style* _style; + + public: + + void addEdge( Edge* edge ) { _edges << edge; } + + void updateEdges( ) + { + foreach ( Edge* edge, _edges ) + edge->update( edge->getSrc( ), edge->getDst( ) ); + } + + protected: + + QList< Edge* > _edges; + + public: + + class AbstractFactory + { + public: + + AbstractFactory( int nodeType, bool defaultFactory = false ) : + _nodeType( nodeType ), _defaultFactory( defaultFactory ) { }; + + virtual ~AbstractFactory( ) { } + + virtual AbstractNode* create( la::Node& node, Style::Manager& styleManager, Style& style, + QGraphicsItem* parent, QGraphicsScene* scene, + QPoint origin, const std::string& label) = 0; + + int getNodeType( ) const { return _nodeType; } + + bool isDefaultFactory( ) const { return _defaultFactory; } + + typedef std::list< AbstractFactory* > List; + + private: + + int _nodeType; + + bool _defaultFactory; + }; + + template < typename T > + class Factory : public AbstractFactory + { + public: + + Factory( int nodeType, bool defaultFactory = false ) : + AbstractFactory( nodeType, defaultFactory ) { } + + virtual AbstractNode* create( la::Node& node, Style::Manager& styleManager, Style& style, + QGraphicsItem* parent, QGraphicsScene* scene, + QPoint origin, const std::string& label ) + { return new T( node, styleManager, style, parent, scene, origin, label ); } + }; + }; + + + + //! Model a rectangular node item on a QT graphics view. + /*! + The following style options are supported: +
    +
  • 'backcolor': Background color, when there is no background image defined. +
  • 'bordercolor': Color of the item border. +
  • 'backimage': Background image (scaled to fit the item size). +
  • 'maximumwidth': Maximum width of the item, content is cropped to fit this with limit. +
  • 'maximumheight': Maximum height of the item, content is cropped to fit this height limit. +
  • 'fontsize': Base size for the font used to display the item label. +
  • 'icon': Display an icon centered in the left of the item. +
  • 'hasshadow': Set this value to false to supress the node shadow. +
+ \nosubgrouping + */ + class Node : public AbstractNode, public QGraphicsRectItem + { + Q_OBJECT + + public: + + Node( la::Node& node, Style::Manager& styleManager, Style& style, + QGraphicsItem* parent, QGraphicsScene* scene, + QPoint origin, const std::string& label ); + + virtual ~Node( ); + + //! Update the node according to a given style and label. + //virtual void update( const std::string& label, const Style& style, Style::Manager& styleManager ); + + QRectF boundingRect() const; + + void paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0 ); + + struct DefaultFactory : public AbstractNode::Factory< Node > + { + DefaultFactory( ) : AbstractNode::Factory< Node >( -1, true ) { } + }; + + private: + + bool hasShadow( ) const { return _shadowColor.isValid( ); } + + protected slots: + + virtual void updateNode( ); + + virtual QGraphicsItem* getGraphicsItem( ) { return this; } + + private: + + QPointF _dimension; + + std::string _label; + + QPixmap _backPixmap; + + QColor _shadowColor; + + double _shadowOffset; + + QTextDocument* _labelDocument; + + QTextLayout* _labelLayout; + + QPixmap _icon; + + protected: + + QVariant itemChange( GraphicsItemChange change, const QVariant& value ); + }; + +} // ::qan::can +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // canItemGeom_h + ============================================================ --- libs/qanava/src/can/canProgressQt.cpp 30308ac7406f7e64d4f9197f8f65348be02412f3 +++ libs/qanava/src/can/canProgressQt.cpp 30308ac7406f7e64d4f9197f8f65348be02412f3 @@ -0,0 +1,79 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canProgressQt.cpp +// \author Benoit Autheman (address@hidden) +// \date 2004 July 08 +//----------------------------------------------------------------------------- + + +// Qarte headers +#include "canProgressQt.h" + + +namespace qan { // ::qan +namespace can { // ::qan::can + + +/* Progress Constructor/Destructor *///---------------------------------------- +ProgressQt::ProgressQt( QApplication* application, QWidget* widget, int maxProgress ) : + qan::utl::Progress( maxProgress ), + _application( application ), + _progress( 0 ) +{ + // Setup progress dialog (Maximum is set to 100, since updateProgress() is called + // directly in percents) + _progress = new QProgressDialog( "Processing...", "Abort", 0, 100, + widget ); + _progress->setMinimumDuration( 0 ); + _progress->setValue( 0 ); +} + +ProgressQt::~ProgressQt( ) +{ + if ( _progress != 0 ) + delete _progress; +} +//----------------------------------------------------------------------------- + + + +/* Views Management *///------------------------------------------------------- +bool ProgressQt::getCancel( ) +{ + return ( _progress != 0 ? _progress->wasCanceled( ) : false ); +} + +void ProgressQt::updateProgress( int percent ) +{ + if ( ( percent < 100 ) && !_progress->isVisible( ) ) + _progress->show( ); + _progress->setValue( percent ); + + if ( _application != 0 ) + _application->processEvents( ); +} +//----------------------------------------------------------------------------- + +} // ::qan::can +} // ::qan + ============================================================ --- libs/qanava/src/can/canProgressQt.h 2bee97ad4bf1c502676b59207f15b8d9f1df8cc0 +++ libs/qanava/src/can/canProgressQt.h 2bee97ad4bf1c502676b59207f15b8d9f1df8cc0 @@ -0,0 +1,96 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file canProgressQt.h +// \author Benoit Autheman (address@hidden) +// \date 2005 July 08 +//----------------------------------------------------------------------------- + + +#ifndef canProgressQt_h +#define canProgressQt_h + + +// LTM headers +#include "../utl/utlProgress.h" + + +// QT headers +#include +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan + namespace can { // ::qan::can + + //! Abstract class used to provide feedback about a task progression. + /*! + \nosubgrouping + */ + class ProgressQt : public qan::utl::Progress + { + /*! \name Progress Constructor/Destructor *///------------------------ + //@{ + public: + + //! ProgressQt constructor. + ProgressQt( QApplication* application, QWidget* widget, int maxProgress = 100 ); + + //! ProgressQt destructor. + virtual ~ProgressQt( ); + + protected: + + //! ProgressQt empty private copy constructor. + ProgressQt( const ProgressQt& progress ) : Progress ( progress ) { } + //@} + //----------------------------------------------------------------- + + + + /*! \name Views Management *///------------------------------------ + //@{ + public: + + //! . + virtual bool getCancel( ); + + QApplication* _application; + + QProgressDialog* _progress; + + protected: + + //! + virtual void updateProgress( int percent ); + //@} + //----------------------------------------------------------------- + }; + + } // ::qan::can +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // canProgressQt_h + ============================================================ --- libs/qanava/src/can/canStyle.cpp 379896dd7657c78e88344dd2ff441f910b512654 +++ libs/qanava/src/can/canStyle.cpp 379896dd7657c78e88344dd2ff441f910b512654 @@ -0,0 +1,370 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qarte software. +// +// \file qanStyle.cpp +// \author Benoit Autheman (address@hidden) +// \date 2005 January 03 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "canStyle.h" + + +// Standard headers +#include + + +// QT headers +#include +#include +#include + + +namespace qan { // ::qan +namespace can { // ::qan::can + + +/* Style Management *///------------------------------------------------------- +void Style::Manager::setStyle( void* object, Style& style ) +{ + if ( getStyle( object ) == 0 ) + { + _objectStyleMap.insert( std::pair< void*, Style* >( object, &style ) ); +// add( style ); // TODO: Check that utl::Manager don't allow duplication + } +} + +Style* Style::Manager::getStyle( void* object ) +{ + ObjectStyleMap::iterator styleIter = _objectStyleMap.find( object ); + if ( styleIter != _objectStyleMap.end( ) ) + return ( *styleIter ).second; + return 0; +} + +const Style* Style::Manager::getStyle( const void* object ) const +{ + ObjectStyleMap::const_iterator styleIter = _objectStyleMap.find( ( void* )object ); + if ( styleIter != _objectStyleMap.end( ) ) + return ( *styleIter ).second; + return 0; +} + +void Style::Manager::setStyle( int type, Style& style ) +{ + // Set the style if the type don't already have a style + if ( getStyle( type ) == 0 ) + { + _typeStyleMap.insert( std::pair< int, Style* >( type, &style ) ); +// add( style ); // TODO: Check that utl::Manager don't allow duplication + } +} + +Style* Style::Manager::getStyle( int type ) +{ + TypeStyleMap::iterator styleIter = _typeStyleMap.find( type ); + if ( styleIter != _typeStyleMap.end( ) ) + return ( *styleIter ).second; + return 0; +} + +const Style* Style::Manager::getStyle( int type ) const +{ + TypeStyleMap::const_iterator styleIter = _typeStyleMap.find( type ); + if ( styleIter != _typeStyleMap.end( ) ) + return ( *styleIter ).second; + return 0; +} +//----------------------------------------------------------------------------- + + +/* Image Caching Management *///----------------------------------------------- +/*! + \return A cached image loaded from the given filename. If fileName is invalid, the returned image can be queried for isNull(). + */ +QImage Style::Manager::getImage( QString fileName ) +{ + NameImageMap::iterator imageIter = _nameImageMap.find( fileName ); + if ( imageIter != _nameImageMap.end( ) ) + return ( *imageIter ).second; + else + { + QImage image( fileName ); + if ( image.isNull( ) ) + return image; + else + { + _nameImageMap.insert( std::pair< QString, QImage >( fileName, image ) ); + return image; + } + } + + return QImage(); +} + +void Style::Manager::clearImages( ) +{ + _nameImageMap.clear( ); +} +//----------------------------------------------------------------------------- + + + +/* Attribute Management *///--------------------------------------------------- +void Style::add( QString name, QVariant variant ) +{ + _nameValueMap.insert( name, variant ); + reset( ); // Force coherent Interview update whitout using (begin/end)Insert() + emit modified( ); +} + +void Style::remove( QString name ) +{ + _nameValueMap.remove( name ); + _imageNames.removeAll( name ); + reset( ); // Force coherent Interview update whitout using (begin/end)Insert() + emit modified( ); +} + +/*! + \return true if the attribute has been renamed, false otherwise (for example, the name was already used by another attribute). + */ +bool Style::rename( QString name, QString newName ) +{ + if ( has( newName ) ) + return false; + + QVariant value = get( name ); + remove( name ); + add( newName, value ); + reset( ); // Force coherent Interview update + return true; +} + +/*! + \return true if a QVariant is registered under the given name, false otherwise. + */ +bool Style::has( QString name ) const +{ + NameValueMap::const_iterator nameIter = _nameValueMap.find( name ); + return ( nameIter != _nameValueMap.end( ) ); +} + +/*! + \return A QVariant registered under a given name, or an invalid QVariant if the name is unknown. + */ +QVariant Style::get( QString name ) +{ + return _nameValueMap.value( name, QVariant( ) ); +} + +/*! + \return A const QVariant registered under a given name, or an invalid QVariant if the name is unknown. + */ +const QVariant Style::get( QString name ) const +{ + /*QVariant result; + NameValueMap::const_iterator nameIter = _nameValueMap.find( name ); + if ( nameIter != _nameValueMap.end( ) ) + result = nameIter->second; + return result;*/ + return _nameValueMap.value( name, QVariant( ) ); +} + +void Style::addColor( QString name, int r, int g, int b ) +{ + QVariant value; + value = QColor( r, g, b ); // QVariant does not support QColor in its ctor (non gui only types) + add( name, value ); +} + +/*! + \return The color registered with name, an invalid Qcolor otherwise. + */ +QColor Style::getColor( QString name ) const +{ + QColor color; + const QVariant& value = get( name ); + if ( value.isValid( ) ) + color = value.value< QColor >( ); + return color; +} + +void Style::addIcon( QString name, QIcon& icon ) +{ + QVariant value; + value = icon; // QVariant does not support gui types in its ctor + add( name, value ); +} + +QIcon Style::getIcon( QString name ) const +{ + QIcon icon; + const QVariant& value = get( name ); + if ( value.isValid( ) ) + icon = value.value< QIcon >( ); + return icon; +} + +void Style::addImage( QString name, QImage image ) +{ + QVariant value; + value = image; // QVariant does not support gui types in its ctor + add( name, value ); +} + +void Style::addImageName( QString name, QString fileName ) +{ + add( name, QVariant( fileName ) ); + _imageNames.push_back( name ); +} +bool Style::hasImageName( QString name ) const +{ + return ( _imageNames.contains( name ) ); +} + +QString Style::getImageName( QString name ) const +{ + if ( hasImageName( name ) ) // Check if name is an image name type + { + QVariant imageName = get( name ); + if ( imageName.type( ) == QVariant::String ) + return imageName.toString( ); + } + return QString( ); +} +//----------------------------------------------------------------------------- + + + +/* Qt Model Interface *///----------------------------------------------------- +QVariant Style::data( const QModelIndex& index, int role ) const +{ + if ( !index.isValid( ) ) + return QVariant( "index invalid" ); + + QVariant d; + + if ( ( role == Qt::FontRole ) && ( index.column( ) == 0 ) ) + { + QFont font; + font.setWeight( QFont::Bold ); + d = font; + } + + if ( role == Qt::DisplayRole ) + { + if ( index.column( ) == 0 ) + { + if ( index.row( ) == 0 ) + d = QString( "name" ); + else + d = _nameValueMap.keys( ).at( index.row( ) - 1 ); + } + else if ( index.column( ) == 1 ) + { + if ( index.row( ) == 0 ) + d = getName( ); + else + d = _nameValueMap.values( ).at( index.row( ) - 1 ); + } + } + + return d; +} + +bool Style::setData( const QModelIndex& index, const QVariant& value, int role ) +{ + if ( index.row( ) == 1 ) + return QAbstractListModel::setData( index, value, role ); + + if ( role == Qt::EditRole && index.column( ) == 1 ) // Edit values + { + QString k = _nameValueMap.keys( ).at( index.row( ) - 1 ); + QVariant v = _nameValueMap.values( ).at( index.row( ) - 1 ); + if ( v.type( ) == value.type( ) ) + { + v = value; + _nameValueMap.insert( k, v ); + emit dataChanged( index, index ); + emit modified( ); + return true; + } + } + if ( role == Qt::EditRole && index.column( ) == 0 ) // Edit names + { + if ( value.type( ) == QVariant::String ) + { + QString k = _nameValueMap.keys( ).at( index.row( ) - 1 ); + if ( rename( k, value.toString( ) ) ) // Rename old name with the editor content and eventually validate the input + { + emit dataChanged( index, index ); + emit modified( ); + return true; + } + } + } + return QAbstractListModel::setData( index, value, role ); +} + +Qt::ItemFlags Style::flags( const QModelIndex &index ) const +{ + if ( !index.isValid( ) ) + return Qt::ItemIsEnabled; + + if ( index.row( ) == 0 ) + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; // First row (style name) is not editable + else + return Qt::ItemIsEnabled | Qt::ItemIsEditable; // Other rows are editable in both the name and value columns + + return Qt::ItemIsEnabled; +} + +QVariant Style::headerData( int section, Qt::Orientation orientation, int role ) const +{ + if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) + { + if ( section == 0 ) + return QString( "Property" ); + else if ( section == 1 ) + return QString( "Value" ); + } + return QVariant( ); +} + +int Style::rowCount( const QModelIndex& parent ) const +{ + return 1 + size( ); +} + +int Style::columnCount( const QModelIndex& parent ) const +{ + return 2; +} +//----------------------------------------------------------------------------- + + + +} // ::qan::can +} // ::qan + ============================================================ --- libs/qanava/src/can/canStyle.h d07d8392e66b0864ba11ed0361491579dd3abadc +++ libs/qanava/src/can/canStyle.h d07d8392e66b0864ba11ed0361491579dd3abadc @@ -0,0 +1,302 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qarte software. +// +// \file qanStyle.h +// \author Benoit Autheman (address@hidden) +// \date 2005 January 03 +//----------------------------------------------------------------------------- + + +#ifndef qan_can_Style_h +#define qan_can_Style_h + + +// UTL headers +#include "../utl/utlManager.h" + + +// QT headers +#include +#include +#include +#include +#include + + +// Std headers +#include + + +//----------------------------------------------------------------------------- +namespace qan // ::qan +{ + namespace can // ::qan::can + { + //! Specify graphic and other attributes for a specific primitive (usually a Canvas Item). + /*! + \nosubgrouping + */ + class Style : public QAbstractListModel + { + Q_OBJECT + + public: + + //! Manage styles for a set of objects (usually graphics items). + /*! + \sa can::Style and can::Positionner + \nosubgrouping + */ + class Manager : public qan::utl::Manager< Style > + { + /*! \name Manager Constructor/Destructor *///------------------ + //@{ + public: + + Manager( ) { } + + virtual ~Manager( ) { clearImages( ); } + //@} + //------------------------------------------------------------- + + + + /*! \name Style Management *///-------------------------------- + //@{ + public: + + //! Set the style for a specific object. + void setStyle( void* object, Style& style ); + + //! Set the style for a specific node type. + void setStyle( int type, Style& style ); + + //! Get the style for a specific object. + Style* getStyle( void* object ); + + //! Get the style for a specific object. + const Style* getStyle( const void* object ) const; + + //! Get the style for a specific node type. + Style* getStyle( int type ); + + //! Get the style for a specific node type. + const Style* getStyle( int type ) const; + + protected: + + //! Map style to their target object. + typedef std::map< void*, Style* > ObjectStyleMap; + + //! Map style to their target object. + typedef std::map< int, Style* > TypeStyleMap; + + //! . + ObjectStyleMap _objectStyleMap; + + //! . + TypeStyleMap _typeStyleMap; + //@} + //------------------------------------------------------------- + + + + /*! \name Image Caching Management *///------------------------ + //@{ + public: + + //! Get an image from its file name or its cached version the second call of the same filename. + QImage getImage( QString fileName ); + + //! Clear this image manager mappings and data (images). + void clearImages( ); + + protected: + + typedef std::map< QString, QImage > NameImageMap; + + //! Map image filename to concrete QT images. + NameImageMap _nameImageMap; + //@} + //------------------------------------------------------------- + }; + + + /*! \name Style Constructor/Destructor *///------------------------ + //@{ + public: + + //! Style constructor. + Style( ) : _name( "" ) { } + + //! Style constructor with name initialisation. + Style( QString name ) : _name( name ) { } + + private: + + //! Style empty private copy constructor. + Style( const Style& style ); + //@} + //----------------------------------------------------------------- + + + + /*! \name Style Name Management *///------------------------------- + //@{ + public: + + //! Get the style name. + QString getName( ) const { return _name; } + + protected: + + //! Style name. + QString _name; + //@} + //----------------------------------------------------------------- + + + + /*! \name Attribute Management *///-------------------------------- + //@{ + public: + + //! Add an attribute and register its name. + template < typename T > + void addT( QString name, T value ) + { + add( name, QVariant( value ) ); + } + + template < typename T > + T getT( QString name ) const + { + QVariant value = get( name ); + if ( value.isValid( ) ) + return value.value< T >( ); + return T( ); + } + + //! Return the number of attributes/value couples registered in this style. + unsigned int size( ) const { return _nameValueMap.size( ); } + + //! Add an attribute and register its name. + void add( QString name, QVariant value ); + + //! Remove a style attribute by name. + void remove( QString name ); + + //! Change an attribute name (changing to an already existing name, has no effect). + bool rename( QString name, QString newName ); + + //! Test if an attribute with a specific name has been set. + bool has( QString name ) const; + + //! Get an attribute by name (invalide QVariant is returned if the name does not exists). + QVariant get( QString name ); + + //! Get an attribute by name (invalide QVariant is returned if the name does not exists). + const QVariant get( QString name ) const; + + //! Specialized version of add() for QColor objects. + void addColor( QString name, int r, int g, int b ); + + //! Get a previously registered QColor by name. + QColor getColor( QString name ) const; + + //! Specialized version of add() for QIcon objects. + void addIcon( QString name, QIcon& icon ); + + //! Get a previously registered QIcon by name. + QIcon getIcon( QString name ) const; + + //! Specialized version of add() for QImage objects. + void addImage( QString name, QImage image ); + + //! Add an image attribute, image loading is delayed until display, and images shared accross styles. + void addImageName( QString name, QString fileName ); + + //! Test if an image name with a specific name has been set. + bool hasImageName( QString name ) const; + + //! . + QString getImageName( QString name ) const; + + protected: + + typedef QMap< QString, QVariant > NameValueMap; + + bool isImageName( QString name ) { return _imageNames.contains( name ); } + + QList< QString > _imageNames; + + //! . + NameValueMap _nameValueMap; + //@} + //----------------------------------------------------------------- + + + /*! \name Qt Model Interface *///---------------------------------- + //@{ + public: + + //! Define the article attribute offset (row) in table. + enum AttributeOffset + { + TITLE = 0, + AUTHOR = 1, + SOURCE = 2, + SUB = 3, + SUP = 4 + }; + + virtual QVariant data( const QModelIndex &index, int role ) const; + + virtual bool setData( const QModelIndex& index, const QVariant& value, int role = Qt::EditRole ); + + virtual Qt::ItemFlags flags( const QModelIndex &index ) const; + + virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + virtual int rowCount( const QModelIndex& parent = QModelIndex( ) ) const; + + virtual int columnCount( const QModelIndex& parent = QModelIndex( ) ) const; + //@} + //----------------------------------------------------------------- + + + /*! \name Model Signals Management *///---------------------------- + //@{ + signals: + + void modified( ); + //@} + //----------------------------------------------------------------- + }; + } // ::qan::can +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // qan_can_Style_h + + ============================================================ --- libs/qanava/src/la/laEdge.cpp 6a89d9b6c76605086f5803912f46f4b8119f2bf3 +++ libs/qanava/src/la/laEdge.cpp 6a89d9b6c76605086f5803912f46f4b8119f2bf3 @@ -0,0 +1,48 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laEdge.cpp +// \author Benoit Autheman (address@hidden) +// \date 2004 February 15 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "./laEdge.h" +#include "./laNode.h" + + +namespace qan { // ::qan +namespace la { // ::qan::la + +void Edge::set( la::Node* src, la::Node* dst ) +{ + if ( src != 0 && dst != 0 ) + { + _src = src; _dst = dst; + src->addOutEdge( *this ); + dst->addInEdge( *this ); + } +} + +} // ::qan::la +} // ::qan ============================================================ --- libs/qanava/src/la/laEdge.h 8ffb7a16203557dd5c09ed82f70df480021973f5 +++ libs/qanava/src/la/laEdge.h 8ffb7a16203557dd5c09ed82f70df480021973f5 @@ -0,0 +1,130 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laEdge.cpp +// \author Benoit Autheman (address@hidden) +// \date 2004 February 15 +//----------------------------------------------------------------------------- + + +#ifndef laEdge_h +#define laEdge_h + + +// Qanava headers +#include "../utl/utlConfig.h" + + +// Standard headers +#include +#include +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan + namespace la { // ::qan::la + + class Node; + + //! Model a weighted directed edge between two nodes. + /*! + \nosubgrouping + */ + class Edge + { + /*! \name Generator Constructor/Destructor *///-------------------- + //@{ + public: + + //! Node constructor with source and destination initialization. + Edge( Node& src, Node& dst, float weight = 1.f ) : + _src( &src ), + _dst( &dst ), + _weight( weight ) + { + + } + + //! Node constructor with source and destination initialization. + Edge( Node* src, Node* dst, float weight = 1.f ) : + _src( src ), + _dst( dst ), + _weight( weight ) + { + + } + + //! STL typedef for a list of la::Edge. + typedef std::list< Edge* > List; + + //! STL typedef for a set of la::Edge. + typedef std::set< Edge* > Set; + //@} + //----------------------------------------------------------------- + + + + /*! \name Source/Destination Management *///----------------------- + //@{ + public: + + //! Get edge source. + Node& getSrc( ) { return *_src; } + + //! Get edge destination. + Node& getDst( ) { return *_dst; } + + //! Get const reference on the edge source. + const Node& getSrc( ) const { return *_src; } + + //! Get const reference on the edge destination. + const Node& getDst( ) const { return *_dst; } + + //! Get edge's weight. + float getWeight( ) const { return _weight; } + + //! Set edge's weight. + void setWeight( float weight ) { _weight = weight; } + + //! Set edge source and destination (use this method carefully it is normally reserved for serialization implementation). + void set( la::Node* src, la::Node* dst ); + + private: + + //! Edge source. + Node* _src; + + //! Edge destination. + Node* _dst; + + //! Edge weight. + float _weight; + //@} + //----------------------------------------------------------------- + }; + } // ::qan::la +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // laEdge_h ============================================================ --- libs/qanava/src/la/laGraph.cpp be2e22c1a71c3c0b8716b2da649942e78e56f48b +++ libs/qanava/src/la/laGraph.cpp be2e22c1a71c3c0b8716b2da649942e78e56f48b @@ -0,0 +1,404 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laGraph.cpp +// \author Benoit Autheman (address@hidden) +// \date 2004 February 15 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "./laGraph.h" + + +// Standard headers +#include + + +// Qt headers +#include + + +namespace qan { // ::qan +namespace la { // ::qan::la + + +/*! \name Helper method for listeners notification *///-------- +void Graph::Listener::notifyNodeInsertedBegin( List& listeners, Node& node ) +{ + for ( List::iterator listenerIter = listeners.begin( ); listenerIter != listeners.end( ); listenerIter++ ) + ( *listenerIter )->nodeInsertedBegin( node ); +} + +void Graph::Listener::notifyNodeInserted( List& listeners, Node& node ) +{ + for ( List::iterator listenerIter = listeners.begin( ); listenerIter != listeners.end( ); listenerIter++ ) + ( *listenerIter )->nodeInserted( node ); +} + +void Graph::Listener::notifyNodeRemovedBegin( List& listeners, Node& node ) +{ + for ( List::iterator listenerIter = listeners.begin( ); listenerIter != listeners.end( ); listenerIter++ ) + ( *listenerIter )->nodeRemovedBegin( node ); +} + +void Graph::Listener::notifyNodeRemoved( List& listeners, Node& node ) +{ + for ( List::iterator listenerIter = listeners.begin( ); listenerIter != listeners.end( ); listenerIter++ ) + ( *listenerIter )->nodeRemoved( node ); +} + +void Graph::Listener::notifyNodeChanged( List& listeners, Node& node ) +{ + for ( List::iterator listenerIter = listeners.begin( ); listenerIter != listeners.end( ); listenerIter++ ) + ( *listenerIter )->nodeChanged( node ); +} +//----------------------------------------------------------------------------- + + + +/* Graph Constructor/Destructor *///------------------------------------------- +Graph::Graph( ) +{ + addAttribute< int >( "Type", 0 ); + addAttribute< std::string >( "Label", std::string( "" ) ); + addAttribute< VectorF >( "Position", VectorF( 2 ) ); + addAttribute< VectorF >( "Dimension", VectorF( 2 ) ); + addAttribute< QDateTime >( "Date", QDateTime( ) ); +} + +Graph::~Graph( ) +{ + for ( Listener::List::iterator listenerIter = _listeners.begin( ); listenerIter != _listeners.end( ); listenerIter++ ) + delete ( *listenerIter ); + _listeners.clear( ); + + clear( ); +} +//----------------------------------------------------------------------------- + + + +/* Edge/Node Management *///--------------------------------------------------- +/*! There is no checking on multiple (same) node addition. + \param node Node to register in this graph. + \param object Optional object that act as a unique key associed to the node. + */ +Node* Graph::insertNode( const std::string& name, int type, bool root, void* object ) +{ + la::Node* node = 0; + if ( type != -1 ) + node = new Node( name, type ); + else + node = new Node( name ); + insertNode( *node, root, object ); + return node; +} + +void Graph::insertNode( la::Node& node, bool root, void* object ) +{ + Listener::notifyNodeInsertedBegin( getListeners( ), node ); + + initNodeAttributes( node ); + + _nodes.push_back( &node ); + _nodesSet.insert( &node ); + + if ( object != 0 ) + setNodeObject( node, object ); + + if ( root ) + addRootNode( node ); + Listener::notifyNodeInserted( getListeners( ), node ); +} + +void Graph::removeNode( Node& node ) +{ + // Test if node subnode will eventually becom root nodes after their super node removal + Node::List rootNodes; + Node::List outNodes; node.collectOutNodes( outNodes ); + for ( Node::List::iterator outNodeIter = outNodes.begin( ); outNodeIter != outNodes.end( ); outNodeIter++ ) + { + Node* outNode = *outNodeIter; + if ( !isRootNode( *outNode ) && outNode->getInDegree( ) <= 1 ) + rootNodes.push_back( outNode ); + } + + // Add orphan out nodes as root node (node is removed to force view update and maintain graph coherency for listeners) + // Oprhan out nodes are removed before 'node' so that they still have a valid parent in + // an eventual associed view (for example in a QAbstractItem view, removing node would cause + // the model to have a gap preventing node out nodes to be destroyed). + for ( Node::List::iterator rootNodeIter = rootNodes.begin( ); rootNodeIter != rootNodes.end( ); rootNodeIter++ ) + { + Node& rootNode = **rootNodeIter; + Listener::notifyNodeInsertedBegin( getListeners( ), rootNode ); + addRootNode( rootNode ); + Listener::notifyNodeInserted( getListeners( ), rootNode ); + } + + + Listener::notifyNodeRemovedBegin( getListeners( ), node ); + + // Disconnect node from its "in edges". + Edge::List::iterator inEdgeIter = node.getInEdges( ).begin( ); + for ( ; inEdgeIter != node.getInEdges( ).end( ); inEdgeIter++ ) + { + la::Edge& inEdge = ( **inEdgeIter ); + inEdge.getSrc( ).getOutEdges( ).remove( &inEdge ); + } + node.getInEdges( ).clear( ); + + // Disconnect node from its "out edges". + Edge::List::iterator outEdgeIter = node.getOutEdges( ).begin( ); + for ( ; outEdgeIter != node.getOutEdges( ).end( ); outEdgeIter++ ) + { + la::Edge& outEdge = ( **outEdgeIter ); + outEdge.getDst( ).getInEdges( ).remove( &outEdge ); + } + node.getOutEdges( ).clear( ); + + // Remove node from the graph various node list + _nodes.remove( &node ); + _nodesSet.erase( &node ); + void* object = findObject( &node ); + if ( object != 0 ) + _objectNodeMap.erase( object ); + _nodeObjectMap.erase( &node ); + removeRootNode( node ); + + Listener::notifyNodeRemoved( getListeners( ), node ); +} + +void Graph::modifyNode( Node& node, const std::string& name, int type, void* object ) +{ + node.setLabel( name ); + + if ( type != -1 ) + node.setType( type ); + + if ( object != 0 ) + setNodeObject( node, object ); + + Listener::notifyNodeChanged( getListeners( ), node ); +} + +void Graph::setNodeObject( Node& node, void* object ) +{ + // Map the registered node to a given memory object that act as a key + if ( object != 0 ) + { + _objectNodeMap.insert( std::pair< void*, Node* >( object, &node ) ); + _nodeObjectMap.insert( std::pair< Node*, void* >( &node, object ) ); + } +} + +Edge* Graph::createEdge( Node& a, Node& b, float weight ) +{ + Edge* edge = new Edge( a, b, weight ); + _edges.push_back( edge ); + a.addOutEdge( *edge ); + b.addInEdge( *edge ); + return edge; +} + +Edge* Graph::createEdge( Node* a, Node* b, float weight ) +{ + Edge* edge = new Edge( a, b, weight ); + _edges.push_back( edge ); + return edge; +} + +void Graph::modifyEdge( Edge& edge, Node& src, Node& dst, float weight ) +{ + // Save destination node topology. + Edge::List inEdges; + std::copy( dst.getInEdges( ).begin( ), dst.getInEdges( ).end( ), std::back_insert_iterator< Edge::List >( inEdges ) ); + Edge::List outEdges; + std::copy( dst.getOutEdges( ).begin( ), dst.getOutEdges( ).end( ), std::back_insert_iterator< Edge::List >( outEdges ) ); + + // Delete the node to force view update (and eventually move the node to its correct position) + void* object = findObject( &dst ); + removeNode( dst ); + + // Restore destination node in and out edges (and reconnect theses edges to their extremity node). + for ( Edge::List::iterator inEdgeIter = inEdges.begin( ); inEdgeIter != inEdges.end( ); inEdgeIter++ ) + { + Edge* inEdge = *inEdgeIter; + dst.addInEdge( *inEdge ); + inEdge->getSrc( ).addOutEdge( *inEdge ); + } + for ( Edge::List::iterator outEdgeIter = outEdges.begin( ); outEdgeIter != outEdges.end( ); outEdgeIter++ ) + { + Edge* outEdge = *outEdgeIter; + dst.addOutEdge( *outEdge ); + outEdge->getDst( ).addInEdge( *outEdge ); + + // Remove (eventually) out node from root node + removeRootNode( outEdge->getDst( ) ); + } + edge.set( &src, &dst ); + edge.setWeight( weight ); + + // Insert back the node to its new correct view position + insertNode( dst, false, object ); +} + +/*! + \return true is there is an edge between a and b (whatever is orientation is), false otherwise. + */ +bool Graph::hasEdge( Node& a, Node& b ) +{ + la::Node::Set adjacentA; + a.getAdjacentNodesSet( adjacentA ); + if ( adjacentA.find( &b ) != adjacentA.end( ) ) + return true; + + la::Node::Set adjacentB; + b.getAdjacentNodesSet( adjacentB ); + if ( adjacentB.find( &a ) != adjacentB.end( ) ) + return true; + + return false; +} + +/*! + \return a pointer on the node of request label. 0 if no such node exists. +*/ +Node* Graph::findNode( const std::string& label ) +{ + for ( Node::List::iterator nodeIter = _nodes.begin( ); nodeIter != _nodes.end( ); nodeIter++ ) + { + Node* node = *nodeIter; + if ( node->getLabel( ) == label ) + return node; + } + return 0; +} + +Node* Graph::findNode( void* object ) +{ + ObjectNodeMap::iterator objectNodeIter = _objectNodeMap.find( object ); + return ( objectNodeIter != _objectNodeMap.end( ) ? objectNodeIter->second : 0 ); +} + +Node* Graph::findNode( int node ) +{ + Node::List::iterator nodeIter = _nodes.begin( ); + int n = 0; + while ( n < node ) + { + nodeIter++; + n++; + } + if ( nodeIter != _nodes.end( ) ) + return *nodeIter; + return 0; +} + +/*! + \result The node index if node is registered in this graph, -1 if there is no node or index. + */ +int Graph::findNode( const Node& node ) const +{ + Node::List::const_iterator nodeIter = _nodes.begin( ); + int n = 0; + while ( nodeIter != _nodes.end( ) && ( *nodeIter != &node ) ) + { + nodeIter++; + n++; + } + if ( nodeIter != _nodes.end( ) ) + return n; + return -1; +} + +void* Graph::findObject( Node* node ) +{ + NodeObjectMap::iterator objectIter = _nodeObjectMap.find( node ); + return ( objectIter != _nodeObjectMap.end( ) ? objectIter->second : 0 ); +} + +/*! + \param node Node to be searched in this graph. + \return true if the node is found, false otherwise. + */ +bool Graph::hasNode( la::Node* node ) const +{ + return ( _nodesSet.find( node ) != _nodesSet.end( ) ); +} + +void Graph::collectNodes( Node::Set& nodes ) const +{ + std::copy( _nodes.begin( ), _nodes.end( ), + std::insert_iterator< Node::Set >( nodes, nodes.begin( ) ) ); +} + +/*! This method clear the nodes, the fast node search cache, the node object mapping + system and the edge list. Registered nodes and edges are not only dereferenced, but + destroyed with a call to delete. + */ +void Graph::clear( ) +{ + _objectNodeMap.clear( ); + _nodeObjectMap.clear( ); + + for ( Edge::List::iterator edgeIter = _edges.begin( ); edgeIter != _edges.end( ); edgeIter++ ) + delete *edgeIter; + _edges.clear( ); + + _nodesSet.clear( ); + for ( Node::List::iterator nodeIter = _nodes.begin( ); nodeIter != _nodes.end( ); nodeIter++ ) + delete *nodeIter; + _nodes.clear( ); +} +//----------------------------------------------------------------------------- + + +/* Root Node Management *///--------------------------------------------------- +/*! + Root nodes manually inserted via addRoot() are cleared from the root nodes (and eventually + automatically re-added if needed). + */ +void Graph::generateRootNodes( ) +{ + _rootNodes.clear( ); + for ( Node::List::iterator nodeIter = _nodes.begin( ); nodeIter != _nodes.end( ); nodeIter++ ) + { + if ( ( *nodeIter )->getInDegree( ) == 0 ) + addRootNode( **nodeIter ); + } +} + +/*! + \param node node that must be tested against the root nodes set (must be a graph node). + \return true if the node is a graph root node, false otherwise. + */ +bool Graph::isRootNode( const la::Node& node ) const +{ + return ( _rootNodesSet.find( const_cast< la::Node* >( &node ) ) != _rootNodesSet.end( ) ); +} +//----------------------------------------------------------------------------- + + +} // ::qan::la +} // ::qan + ============================================================ --- libs/qanava/src/la/laGraph.h e25200416eafafdee8d09d801f1268bf67eb334d +++ libs/qanava/src/la/laGraph.h e25200416eafafdee8d09d801f1268bf67eb334d @@ -0,0 +1,347 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laGraph.h +// \author Benoit Autheman (address@hidden) +// \date 2004 February 15 +//----------------------------------------------------------------------------- + + +#ifndef laGraph_h +#define laGraph_h + + +// Qanava headers +#include "./laEdge.h" +#include "./laNode.h" + + +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan + namespace la { // ::qan::la + + class Graph; + + //! Model a standard weighted directed graph using a node-list, edge-list representation. + /*! + \nosubgrouping + */ + class Graph + { + public: + + //! Catch significative node and edge operations from a Graph object. + /*! + \nosubgrouping + */ + class Listener + { + /*! \name Notification Management *///------------------------- + //@{ + public: + + //! Listener constructor with listenned graph initialization. + Listener( Graph& graph ) : _graph( graph ) { } + + virtual ~Listener( ) { } + + //! Get this listener graph. + Graph& getGraph( ) { return _graph; } + + virtual void nodeInsertedBegin( Node& node ) = 0; + + virtual void nodeInserted( Node& node ) = 0; + + virtual void nodeRemovedBegin( Node& node ) = 0; + + virtual void nodeRemoved( Node& node ) = 0; + + //! Node data have changed (node or edge insertion and suppression don't trigger this notification). + virtual void nodeChanged( Node& node ) = 0; + + typedef std::list< Listener* > List; + + private: + + Graph& _graph; + //@} + //------------------------------------------------------------- + + + /*! \name Helper method for listeners notification *///-------- + //@{ + public: // In fact this should protected, but GCC don't allow declaration of outer class as friend in an inner class. + + static void notifyNodeInsertedBegin( List& listeners, Node& node ); + + static void notifyNodeInserted( List& listeners, Node& node ); + + static void notifyNodeRemovedBegin( List& listeners, Node& node ); + + static void notifyNodeRemoved( List& listeners, Node& node ); + + static void notifyNodeChanged( List& listeners, Node& node ); + //@} + //------------------------------------------------------------- + }; + + /*! \name Graph Constructor/Destructor *///------------------------ + //@{ + public: + + //! Graph default constructor. + Graph( ); + + //! Graph default destructor. All registered nodes and edges are invalid after graph destruction. + ~Graph( ); + + private: + + //! Graph empty private copy constructor. + Graph( const Graph& graph ); + //@} + //----------------------------------------------------------------- + + + + /*! \name Edge/Node Management *///-------------------------------- + //@{ + public: + + //! Clear the graph from all its edges and nodes. + void clear( ); + + //! Register a node in this graph a map it to an optional exisiting object in memory. + Node* insertNode( const std::string& name, int type = -1, bool root = false, void* object = 0 ); + + //! Register a node in this graph a map it to an optional exisiting object in memory. + void insertNode( la::Node& node, bool root = false, void* object = 0 ); + + //! Remove a node from the graph (node is not deleted). + void removeNode( Node& node ); + + //! Change node properties and notify graph's listener that some data have changed in the node. + void modifyNode( Node& node, const std::string& name, int type = -1, void* object = 0 ); + + //! Set a node object unique key. + void setNodeObject( Node& node, void* object ); + + //! Graph's edges factory. + Edge* createEdge( Node& a, Node& b, float weight = 1.f ); + + //! Graph's edges factory (a and b can be set to 0 and initialized later). + Edge* createEdge( Node* a, Node* b, float weight = 1.f ); + + void modifyEdge( Edge& edge, Node& a, Node& b, float weight = 1.f ); + + //! Remove an edge from this graph. + void removeEdge( Edge& edge ); + + //! Test if there is an edge between nodes a and b (whatever its orientation is). + bool hasEdge( Node& a, Node& b ); + + //! Set this graph listener (listener become owned by this graph). + void addListener( Listener* listener ) { _listeners.push_back( listener ); } + + //! Get this graph current listeners. + Listener::List& getListeners( ) { return _listeners; } + + typedef std::list< Graph* > List; + + private: + + //! List of nodes currently registered in this graph. + Node::List _nodes; + + //! Set of nodes currently registered in this graph (used for fast node search). + Node::Set _nodesSet; + + //! Map an object to its associed node. + typedef std::map< void*, Node* > ObjectNodeMap; + + //! . + typedef std::map< Node*, void* > NodeObjectMap; + + //! Map an object to its associed graph node. + ObjectNodeMap _objectNodeMap; + + //! . + NodeObjectMap _nodeObjectMap; + + //! List of edges currently connecting the registered nodes in this graph. + Edge::List _edges; + + //! Listener currently registered for this graph. + Listener::List _listeners; + //@} + //----------------------------------------------------------------- + + + + /*! \name Graph Consultation Management *///----------------------- + //@{ + public: + + //! Get graph node count. + unsigned int getNodeCount( ) const { return _nodes.size( ); } + + //! Get graph's nodes list (list must be used read-only). + Node::List& getNodes( ) { return _nodes; } + + //! Get graph's edges list (list must be used read-only). + Edge::List& getEdges( ) { return _edges; } + + //! Collect a set of unique node registered in this graph. + void collectNodes( Node::Set& nodes ) const; + //@} + //----------------------------------------------------------------- + + + + /*! \name Search Management *///----------------------------------- + //@{ + public: + + //! Find a node of a given label in the graph. + Node* findNode( const std::string& label ); + + //! Find a node given its associed key memory object (if such key has been specified during node adjunction). + Node* findNode( void* object ); + + //! Find the nth registered node in this graph (For internal use only). + /*! This method should only be used in repositories just after node loading when their initial order has not been altered. */ + Node* findNode( int node ); + + //! Get the index where a node is currently registered in this graph. + /*! This method should only be used in repositories just after node loading when their initial order has not been altered. */ + int findNode( const Node& node ) const; + + //! Find a node object for a specific node (if such an object has been specified during node adjunction). + void* findObject( Node* node ); + + //! Search for a specific node in this graph and return true if the node is found. + bool hasNode( la::Node* node ) const; + //@} + //----------------------------------------------------------------- + + + + /*! \name Root Node Management *///-------------------------------- + //@{ + public: + + //! Add a root to this graph (ie a node that don't have super nodes.) + /*! \param node must be already registered in the graph. */ + void addRootNode( la::Node& node ) { _rootNodes.push_back( &node ); _rootNodesSet.insert( &node ); } + + //! Remove a node from the root node list + void removeRootNode( la::Node& node ) { _rootNodes.remove( &node ); _rootNodesSet.erase( &node ); } + + //! Get the currently registered root node for this graph. + Node::List& getRootNodes( ) { return _rootNodes; } + + //! Get the currently registered root node for this graph. + Node::Set& getRootNodesSet( ) { return _rootNodesSet; } + + //! Generate the root set by automatically looking for nodes with no super nodes (O(n), n numbers of nodes). + void generateRootNodes( ); + + //! Test if a given node is a graph root node. + bool isRootNode( const la::Node& node ) const; + + private: + + //! Ordered root nodes for this graph's subgraphs. + Node::List _rootNodes; + + //! Root nodes of graph's subgraphs (used only to test root node existence). + Node::Set _rootNodesSet; + //@} + //----------------------------------------------------------------- + + + /*! \name Node Attributes Management *///-------------------------- + //@{ + public: + + template < typename T > + void addAttribute( const std::string& name, T t ) + { + _attributesNames.push_back( name ); + for ( Node::List::iterator nodeIter = getNodes( ).begin( ); nodeIter != getNodes( ).end( ); nodeIter++ ) + ( *nodeIter )->addAttribute< T >( t ); + } + + std::string getAttributeName( unsigned int role ) + { + return ( role < _attributesNames.size( ) ? _attributesNames[ role ] : std::string( "" ) ); + } + + template < typename T > + void setAttribute( Node* node, const std::string& name, T& value ) + { + int role = hasAttribute( name ); + if ( role >= 0) + setAttribute< T >( node, role, value ); + } + + template < typename T > + void setAttribute( Node* node, unsigned int role, T& value ) + { + node->setAttribute< T >( role, value ); + } + + int hasAttribute( const std::string& name ) const + { + int r = 0; + Strings::const_iterator nameIter = _attributesNames.begin( ); + for ( ; nameIter != _attributesNames.end( ); nameIter++, r++ ) + if ( *nameIter == name ) + return r; + return -1; + } + + unsigned int getAttributesCount( ) const { return _attributesNames.size( ); } + + protected: + + void initNodeAttributes( Node& node ) + { + node.initAttributes( _attributesNames.size( ) ); + } + + typedef std::vector< std::string > Strings; + + Strings _attributesNames; + //@} + //----------------------------------------------------------------- + }; + } // ::qan::la +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // laGraph_h + ============================================================ --- libs/qanava/src/la/laGrid.cpp 5e32dd40c64db52ff4db4735ef58dc489ec18bd5 +++ libs/qanava/src/la/laGrid.cpp 5e32dd40c64db52ff4db4735ef58dc489ec18bd5 @@ -0,0 +1,39 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laGrid.cpp +// \author Benoit Autheman (address@hidden) +// \date 2004 December 05 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "./laGrid.h" + + +namespace qan { // ::qan +namespace la { // ::qan::la + + +} // ::qan::la +} // ::qan + ============================================================ --- libs/qanava/src/la/laGrid.h b22d655feab86d7cab3e4581fd87b3efcffe573f +++ libs/qanava/src/la/laGrid.h b22d655feab86d7cab3e4581fd87b3efcffe573f @@ -0,0 +1,111 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laGrid.h +// \author Benoit Autheman (address@hidden) +// \date 2004 December 05 +//----------------------------------------------------------------------------- + + +#ifndef laGrid_h +#define laGrid_h + + +// QT headers +#include +#include +#include +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan + namespace la { // ::qan::la + + + //! Defines the necessary methods to build a grid on a virtual canvas (draw lines, text, manage resizing, etc.). + /*! + Grid geometry is added dynamically using virtual methods addLine(), addRectangle() and addText() implemented + in a concrete grid for a particular graphic subsystem (for exemple QT GraphicsView and can::GridCheckBoard). + + \sa GridCheckBoard + \nosubgrouping + */ + class Grid + { + /*! \name Grid Constructor and Destructor *///------------------------- + //@{ + public: + + //! Grid constructor with eventual layout initialization. + Grid( ) { } + + //! Grid destructor. + virtual ~Grid( ) { } + + private: + + Grid( const Grid& g ); + //@} + //--------------------------------------------------------------------- + + + + /*! \name Layout and Size Management *///----------------------------- + //@{ + public: + + //! Resize the grid (ie, take care of resizing the specified horizontal and vertical lines, and notify the grid layout of the resize). + virtual void resize( QSizeF s ) { } + //@} + //--------------------------------------------------------------------- + + + + /*! \name Grid Construction Management *///--------------------------- + //@{ + public: + + //! Add a grid line on the canvas with specific line settings. + virtual void addLine( QLineF l, float w = 1, bool dash = false, bool dot = false ) = 0; + + //! Add a grid rectangle on the canvas with specific size and color settings. + virtual void addRectangle( QRectF r, QColor c ) = 0; + + //! Add a grid text label on the canvas. + virtual void addText( const std::string& text, QPointF p, bool bold = false ) = 0; + + //! Add an horizontal line to the grid canvas (horizontal lines are automatically resized when the grid canvas is resized). + virtual void addHorizontalLine( QLineF l, int w = 1, bool dash = false, bool dot = false ) = 0; + + //! Add a vertical line to the grid canvas (vertical lines are automatically resized when the grid canvas is resized). + virtual void addVerticalLine( QLineF l, int w = 1, bool dash = false, bool dot = false ) = 0; + //@} + //--------------------------------------------------------------------- + }; + } // ::qan::la +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // laGrid_h + ============================================================ --- libs/qanava/src/la/laLayout.cpp 952b2d3a34c69bee229fb8ea0ab77ecab1154eac +++ libs/qanava/src/la/laLayout.cpp 952b2d3a34c69bee229fb8ea0ab77ecab1154eac @@ -0,0 +1,438 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laLayout.cpp +// \author Benoit Autheman (address@hidden) +// \date 2004 May 22 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "./laLayout.h" + + +// Std headers +#include +#include +#include + + +namespace qan { // ::qan +namespace la { // ::qan::la + + +/* Layout Generation Management *///------------------------------------------- +void Layout::resetNodesPositions( la::Graph& graph ) +{ + Node::List& nodes = graph.getNodes( ); + for ( Node::List::iterator nodeIter = nodes.begin( ); nodeIter != nodes.end( ); nodeIter++ ) + ( *nodeIter )->setPosition( -1.0f, -1.0f ); +} +//----------------------------------------------------------------------------- + + + +/* Random Layout Generation Management *///------------------------------------ +void Random::layout( la::Graph& graph, la::Grid& grid, QRectF r, utl::Progress&, int step ) +{ + // Create a random layout + srand( QDateTime::currentDateTime( ).toTime_t( ) ); + + Node::List& nodes = graph.getNodes( ); + for ( Node::List::iterator nodeIter = nodes.begin( ); nodeIter != nodes.end( ); nodeIter++ ) + { + Node* node = *nodeIter; + + float w = ( float )( ( rand( ) % 100 ) / 100.0 * r.width( ) ); + float h = ( float )( ( rand( ) % 100 ) / 100.0 * r.height( ) ); + node->setPosition( w, h ); + } +} +//----------------------------------------------------------------------------- + + + +/* Concentric Layout Management *///------------------------------------------- +void Concentric::layout( la::Graph& graph, la::Grid& grid, QRectF r, utl::Progress& progress, int step ) +{ + // Configure the progress monitor + progress.setProgress( 0 ); + progress.setMaxProgress( graph.getNodeCount( ) ); + + //double centerX = r.width( ) / 2.; + //double centerY = r.height( ) / 2.; + QPointF center = r.center( ); + int nodesPerCircle = 360 / _azimutDelta; + Node::List::iterator nodeIter = graph.getNodes( ).begin( ); + for ( int n = 0; n < ( int )graph.getNodes( ).size( ); n++, nodeIter++ ) + { + la::Node& node = **nodeIter; + double azimutIndex = ( n % nodesPerCircle ); + double azimut = azimutIndex * _azimutDelta; + + int circleIndex = 1 + ( n / nodesPerCircle ); + double cx = sin( azimut * 3.14156 / 180. ) * ( circleIndex * _circleInterval ); + double cy = cos( azimut * 3.14156 / 180. ) * ( circleIndex * _circleInterval ); + + node.getPosition( )( 0 ) = center.x( ) + cx; + node.getPosition( )( 1 ) = center.y( ) + cy; + progress.incProgress( ); + } + + progress.finish( ); +} +//----------------------------------------------------------------------------- + + + +/* Colimacon Layout Management *///-------------------------------------------- +void Colimacon::layout( la::Graph& graph, la::Grid& grid, QRectF r, utl::Progress& progress, int step ) +{ + // Configure the progress monitor + progress.setProgress( 0 ); + progress.setMaxProgress( graph.getNodeCount( ) ); + + QPointF center = r.center( ); + int nodesPerCircle = 360 / _azimutDelta; + Node::List::iterator nodeIter = graph.getNodes( ).begin( ); + for ( int n = 0; n < ( int )graph.getNodes( ).size( ); n++, nodeIter++ ) + { + la::Node& node = **nodeIter; + double azimutIndex = ( n % nodesPerCircle ); + double azimut = n * _azimutDelta; + + int circleIndex = 1 + ( n / nodesPerCircle ); + double cx = sin( azimut * 3.14156 / 180. ) * ( log( 1. + n ) * 10 * _circleInterval ); + double cy = cos( azimut * 3.14156 / 180. ) * ( log( 1. + n ) * 10 * _circleInterval ); + + node.getPosition( )( 0 ) = center.x( ) + cx; + node.getPosition( )( 1 ) = center.y( ) + cy; + progress.incProgress( ); + } + + progress.finish( ); +} +//----------------------------------------------------------------------------- + + + +/* Hierarchy Layout Generation Management *///--------------------------------- +void DirectedTree::layout( la::Graph& graph, la::Grid&, QRectF r, utl::Progress& progress, int step ) +{ + // Configure the progress monitor + progress.setProgress( 0 ); + progress.setMaxProgress( graph.getNodeCount( ) ); + + // Reset the graph nodes positions (If position are not resetted, nodes are all considered + // already placed + resetNodesPositions( graph ); + + // Configure tree bounding box + VectorF& bbox = *new VectorF( 4 ); + bbox( 0 ) = getXOrigin( ); + bbox( 1 ) = getYOrigin( ); + + // Layout all graph subgraph + Node::List& rootNodes = graph.getRootNodes( ); + for ( Node::List::iterator rootsIter = rootNodes.begin( ); rootsIter != rootNodes.end( ); rootsIter++ ) + { + layout( **rootsIter, bbox, 0, progress ); + bbox( 0 ) += getXSpacing( ); + } + + // Set graph oritentation + if ( _orientation == HORIZONTAL ) + transpose( graph ); + delete &bbox; + + progress.finish( ); +} + +void DirectedTree::layout( la::Node& node, VectorF& bbox, int depth, utl::Progress& progress ) +{ + if ( _marked.find( &node ) != _marked.end( ) ) + return; + _marked.insert( &node ); + + if ( getStopRecusrion( ) ) + return; + + float xStart = bbox( 0 ); + + // Depth first + int laidOut = 0; + Node::Set outNodes; node.collectOutNodesSet( outNodes ); + for ( Node::Set::iterator outNodesIter = outNodes.begin( ); outNodesIter != outNodes.end( ); outNodesIter++ ) + { + Node& subNode = **outNodesIter; + + // Detect if the node has already been placed + if ( subNode.getPosition( )( 0 ) < 0.f && + subNode.getPosition( )( 1 ) < 0.f ) + { + // A leaf node must be drawn at x+dx if one or more nodes has previously been laid out (!=begin). + if ( laidOut > 0 ) + bbox( 0 ) += getXSpacing( ); + + layout( subNode, bbox, depth + 1, progress ); + laidOut++; + } + } + + float xEnd = bbox( 0 ); + + // Detect leaf node + float x = 0.f; + float y = getYOrigin( ) + ( getYSpacing( ) * depth ); + if ( node.isLeaf( ) ) + x = xStart; + else + x = xStart + ( ( xEnd - xStart ) / 2.f ); + node.setPosition( x, y ); + + // Updated progress monitor + progress.incProgress( ); + if ( progress.getCancel( ) ) + stopRecursion( ); +} + +void DirectedTree::transpose( la::Graph& graph ) +{ + Node::List& nodes = graph.getNodes( ); + for ( Node::List::iterator nodeIter = nodes.begin( ); nodeIter != nodes.end( ); nodeIter++ ) + { + Node& node = **nodeIter; + VectorF position = node.getPosition( ); + node.setPosition( position( 1 ), position( 0 ) ); + } +} +//----------------------------------------------------------------------------- + + + +/* Force Layout Generation Management *///------------------------------------- +/*! Initial positions will be generated using a fixed layout (random or colimacon) if step is + superior of 1. + */ +void UndirectedGraph::layout( la::Graph& graph, la::Grid& grid, QRectF r, utl::Progress& progress, int step ) +{ + int runCount = 50; + if ( step != -1 ) + runCount = step; + progress.setProgress( 0 ); + progress.setMaxProgress( runCount ); + + // Generate a random layout for algorithm initialisation + if ( runCount > 1 ) + { + //Random initalLayout; + Colimacon initalLayout; + initalLayout.layout( graph, grid, r, progress ); + } + + // Apply the spring force algorithm + std::vector< VectorF > positions; + positions.reserve( graph.getNodeCount( ) + 1 ); // Last position reserved for a virtual center node + unsigned int n = 0; + for ( ; n < graph.getNodeCount( ) + 1; n++ ) + positions.push_back( VectorF( 2 ) ); + la::Node::Set nodesSet; graph.collectNodes( nodesSet ); + + _center.setPosition( r.width( ) / 2, r.height( ) / 2 ); + //_center.setPosition( 100., 100. ); + Node::List& nodes = graph.getNodes( ); + for ( int iter = 0; iter < runCount; iter++ ) + { + double modification = 0.; + + // Compute new nodes positions using the spring embedder model + Node::List::iterator nodeIter = nodes.begin( ); + for ( n = 0; nodeIter != nodes.end( ); n++, nodeIter++ ) + { + la::Node& node = **nodeIter; + + Node::Set adjacentNodes; + node.getAdjacentNodesSet( adjacentNodes ); + if ( graph.isRootNode( node ) ) + adjacentNodes.insert( &_center ); + VectorF fspring = computeSpringForce( node, adjacentNodes, graph ); + VectorF frep = computeRepulseForce( node, adjacentNodes, nodesSet, graph ); + + VectorF delta( 2 ); + delta = ( frep + fspring ) / ( float )( nodes.size( ) + 1.f ); + positions[ n ] = node.getPosition( ) + delta; + modification += length2( delta ); + } + + // Apply modifications for a virtual center node connected to all root nodes + { + n = nodes.size( ); + VectorF fspring = computeSpringForce( _center, graph.getRootNodesSet( ), graph ); + VectorF frep = computeRepulseForce( _center, graph.getRootNodesSet( ), nodesSet, graph ); + + VectorF delta( 2 ); + delta = ( frep + fspring ) / ( float )( nodes.size( ) + 1.f ); + positions[ n ] = _center.getPosition( ) + delta; + } + + // Move the nodes to their new positions + int p = 0; + for ( nodeIter = nodes.begin( ); nodeIter != nodes.end( ); nodeIter++, p++ ) + ( *nodeIter )->setPosition( positions[ p ] ); + _center.setPosition( positions[ nodes.size( ) ] ); + + // Stop iterating if node have converged to a fixed position + if ( modification < ( 5. * nodes.size( ) ) ) + break; + + // Update progress bar + progress.incProgress( ); + + // Detect process interruption + if ( progress.getCancel( ) ) + break; + } + + // Project the graph in the view coordinate system (translate and scale) + if ( false ) // No longer necessary with GraphicsView + { + VectorF layoutBBoxMin( 2 ), layoutBBoxMax( 2 ); + + computeBoundingBox( positions, layoutBBoxMin, layoutBBoxMax ); + + if ( ( layoutBBoxMin( 0 ) < 0 ) || ( layoutBBoxMin( 1 ) < 0 ) || + ( layoutBBoxMax( 0 ) > r.width( ) ) || ( layoutBBoxMax( 1 ) > r.height( ) ) ) + { + VectorF scale( 2 ); + + // BUG: scale peut etre > 1 ce qui n'est pas une situation saine (source bug ?). + scale( 0 ) = r.width( ) / ( layoutBBoxMax( 0 ) - layoutBBoxMin( 0 ) ); + scale( 1 ) = r.height( ) / ( layoutBBoxMax( 1 ) - layoutBBoxMin( 1 ) ); + + // Translate the layout to have only positive coordinates + for ( Node::List::iterator nodeIter = nodes.begin( ); nodeIter != nodes.end( ); nodeIter++ ) + { + la::Node& node = **nodeIter; + VectorF& nodePosition = node.getPosition( ); + nodePosition -= layoutBBoxMin; + nodePosition *= scale; + } + VectorF& centerPosition = positions[ nodes.size( ) ]; + centerPosition -= layoutBBoxMin; + centerPosition *= scale; + _center.setPosition( centerPosition ); + } + } + + progress.finish( ); +} + +void UndirectedGraph::computeBoundingBox( std::vector< VectorF >& positions, VectorF& min, VectorF& max ) +{ + min( 0 ) = min( 1 ) = 9999999999.f; + max( 0 ) = max( 1 ) = -9999999999.f; + + for ( unsigned int p = 0; p < positions.size( ); p++ ) + { + VectorF& position = positions[ p ]; + if ( position( 0 ) < min( 0 ) ) + min( 0 ) = position( 0 ); + if ( position( 1 ) < min( 1 ) ) + min( 1 ) = position( 1 ); + + if ( position( 0 ) > max( 0 ) ) + max( 0 ) = position( 0 ); + if ( position( 1 ) > max( 1 ) ) + max( 1 ) = position( 1 ); + } +} + +VectorF UndirectedGraph::computeRepulseForce( la::Node& u, la::Node::Set& adjacentNodes, la::Node::Set& nodes, la::Graph& graph ) +{ + VectorF force( 2 ); + force( 0 ) = force( 1 ) = 0.f; + + // Compute repulsion forces for all non adjacent nodes + la::Node::Set nonAdjacentNodes; + std::set_difference( nodes.begin( ), nodes.end( ), adjacentNodes.begin( ), adjacentNodes.end( ), std::inserter( nonAdjacentNodes, nonAdjacentNodes.begin( ) ) ); + if ( !graph.isRootNode( u ) ) + nonAdjacentNodes.insert( &_center ); + + la::Node::Set::iterator nonAdjacentNodeIter = nonAdjacentNodes.begin( ); + for ( ; nonAdjacentNodeIter != nonAdjacentNodes.end( ); nonAdjacentNodeIter++ ) + { + la::Node& v = **nonAdjacentNodeIter; + if ( &v == &u ) + continue; + + // Compute repulsion forces between item and + VectorF& pu = u.getPosition( ); + VectorF& pv = v.getPosition( ); + VectorF uv = pv - pu; + uv *= - ( 80 * 80 ) / ( 1.0 + length2( uv ) ); + force += uv; + } + return force; +} + +VectorF UndirectedGraph::computeSpringForce( la::Node& u, la::Node::Set& adjacentNodes, la::Graph& graph ) +{ + VectorF force( 2 ); + force( 0 ) = 0.f; force( 1 ) = 0.f; + + // Compute attraction forces for all adjacent nodes (roots nodes are considered adjacents) + la::Node::Set::iterator adjacentNodeIter = adjacentNodes.begin( ); + for ( ; adjacentNodeIter != adjacentNodes.end( ); adjacentNodeIter++ ) + { + la::Node& v = **adjacentNodeIter; + + // Compute attraction forces between item and + VectorF& pu = u.getPosition( ); + VectorF& pv = v.getPosition( ); + VectorF uv = pv - pu; + + double l = length( uv ) / 100.f; + double size = 1.; + if ( l > 1.0 ) + size = 2.f * log( l ); + + uv *= size; + force += uv; + } + + return force; +} + +float UndirectedGraph::length( const VectorF& v ) +{ + return sqrt( ( v( 0 ) * v( 0 ) ) + ( v( 1 ) * v( 1 ) ) ); +} + +float UndirectedGraph::length2( const VectorF& v ) +{ + return ( v( 0 ) * v( 0 ) ) + ( v( 1 ) * v( 1 ) ); +} +//----------------------------------------------------------------------------- + + +} // ::qan::la +} // ::qan ============================================================ --- libs/qanava/src/la/laLayout.h 28ef82ee266b4918b0a5cc146c6f8528dc8ee26f +++ libs/qanava/src/la/laLayout.h 28ef82ee266b4918b0a5cc146c6f8528dc8ee26f @@ -0,0 +1,343 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laLayout.h +// \author Benoit Autheman (address@hidden) +// \date 2004 May 22 +//----------------------------------------------------------------------------- + + +#ifndef laLayout_h +#define laLayout_h + + +// Qanava headers +#include "../utl/utlProgress.h" +#include "./laGraph.h" +#include "./laGrid.h" + + +// STD headers +#include + + +// QT headers +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan + namespace la { // ::qan::la + + //! Abstract interface defining a graph layout algorithm (placement of node in space). + /*! + \nosubgrouping + */ + class Layout + { + public: + + /*! \name Layout Constructor/Destructor *///--------------------------- + //@{ + //! Layout constructor. + Layout( ) { } + + //! Layout virtual destructor. + virtual ~Layout( ) { } + + private: + + Layout( const Layout& l ); + //@} + //--------------------------------------------------------------------- + + + + /*! \name Layout Generation Management *///---------------------------- + //@{ + public: + + //! Layout nodes from a given graph using r as a clipping rect, and update grid. + virtual void layout( la::Graph& graph, la::Grid& grid, + QRectF r, utl::Progress& progress, int step = -1 ) = 0; + + protected: + + //! Reset all nodes positions. + static void resetNodesPositions( la::Graph& graph ); + //@} + //--------------------------------------------------------------------- + }; + + + + //! Randomly layout an undirected graph. + /*! + \nosubgrouping + */ + class Random : public Layout + { + /*! \name Random Constructor/Destructor *///--------------------------- + //@{ + public: + + //! Random constructor. + Random( ) : Layout( ) { } + //@} + //--------------------------------------------------------------------- + + + + /*! \name Random Layout Generation Management *///--------------------- + //@{ + public: + + //! . + virtual void layout( la::Graph& graph, la::Grid& grid, + QRectF r, utl::Progress& progress, int step = -1 ); + //@} + //--------------------------------------------------------------------- + }; + + + //! Layout a graph as concentric circles of nodes. + /*! + \nosubgrouping + */ + class Concentric : public Layout + { + /*! \name Concentric Constructor/Destructor *///----------------------- + //@{ + public: + + //! Concentric constructor. + Concentric( double azimutDelta = 45., double circleInterval = 50. ) : + Layout( ), _azimutDelta( azimutDelta ), _circleInterval( circleInterval ) { } + + private: + + double _azimutDelta; + + double _circleInterval; + //@} + //--------------------------------------------------------------------- + + + + /*! \name Concentric Layout Management *///---------------------------- + //@{ + public: + + //! . + virtual void layout( la::Graph& graph, la::Grid& grid, + QRectF r, utl::Progress& progress, int step = -1 ); + //@} + //--------------------------------------------------------------------- + }; + + + //! Layout nodes in a (logarithm) colimacon. + /*! + \nosubgrouping + */ + class Colimacon : public Layout + { + /*! \name Colimacon Constructor/Destructor *///------------------------ + //@{ + public: + + //! Colimacon constructor. + Colimacon( double azimutDelta = 15., double circleInterval = 10. ) : + Layout( ), _azimutDelta( azimutDelta ), _circleInterval( circleInterval ) { } + + private: + + double _azimutDelta; + + double _circleInterval; + //@} + //--------------------------------------------------------------------- + + + + /*! \name Colimacon Layout Management *///----------------------------- + //@{ + public: + + //! . + virtual void layout( la::Graph& graph, la::Grid& grid, + QRectF r, utl::Progress& progress, int step = -1 ); + //@} + //--------------------------------------------------------------------- + }; + + + //! Layout an undirected graph as a directed top-down tree. + /*! + \nosubgrouping + */ + class DirectedTree : public Layout + { + /*! \name DirectedTree Constructor/Destructor *///--------------------- + //@{ + public: + + //! Define layout orientation. + enum Orientation + { + //! . + NONE = 0, + + //! . + HORIZONTAL = 1, + + //! . + VERTICAL = 2 + }; + + //! DirectedTree constructor with orientation initialization. + /*! \param spacing spacing between node on x and y (ex: 120, 70 with VERTICAL). */ + DirectedTree( const VectorF& spacing, Orientation orientation ) : + Layout( ), _origin( 2 ), _spacing( spacing ), _orientation( orientation ), _stopRecursion( false ) { _origin( 0 ) = 0.f; _origin( 1 ) = 0.f; } + + //! DirectedTree constructor with origin and orientation initialization. + /*! \param spacing spacing between node on x and y (ex: 120, 70 with VERTICAL). */ + DirectedTree( const VectorF& origin, const VectorF& spacing, Orientation orientation ) : + Layout( ), _origin( origin ), _spacing( spacing ), _orientation( orientation ), _stopRecursion( false ) { } + + private: + + VectorF _origin; + //@} + //--------------------------------------------------------------------- + + + + /*! \name Hierarchy Layout Generation Management *///------------------ + //@{ + public: + + //! Layout a graph as a hierarchy tree. + virtual void layout( la::Graph& graph, la::Grid& grid, + QRectF r, utl::Progress& progress, int step = -1 ); + + protected: + + //! Layout a node hierarchy as a hierarchy tree. + void layout( la::Node& node, VectorF& bbox, int depth, utl::Progress& progress ); + + //! Invert the x/y coordinates to set the desired orientation. + static void transpose( la::Graph& graph ); + + //! Spacing on x and y between tree nodes. + VectorF _spacing; + + //! Generated tree orientation. + Orientation _orientation; + + //! Container for already laid out nodes. + la::Node::Set _marked; + + private: + + //! Get the 'x' horizontal spacing according to the current orientation. + float getXSpacing( ) const { return ( _orientation == HORIZONTAL ? _spacing( 1 ) : _spacing( 0 ) ); } + + //! Get the 'y' vertical spacing according to the current orientation. + float getYSpacing( ) const{ return ( _orientation == HORIZONTAL ? _spacing( 0 ) : _spacing( 1 ) ); } + + //! Get the 'x' horizontal origin according to the current orientation. + float getXOrigin( ) const { return ( _orientation == HORIZONTAL ? _origin( 1 ) : _origin( 0 ) ); } + + //! Get the 'y' vertical origin according to the current orientation. + float getYOrigin( ) const { return ( _orientation == HORIZONTAL ? _origin( 0 ) : _origin( 1 ) ); } + + //! Force the tree layout algorithm to stop recursion. + void stopRecursion( ) { _stopRecursion = true; } + + //! Return the value of the stop recursion flag. + bool getStopRecusrion( ) const { return _stopRecursion; } + + //! Indicate that the algorithm execution is canceled and that the layout algorithm recusrion must stop. + bool _stopRecursion; + //@} + //--------------------------------------------------------------------- + }; + + + + //! Layout an undirected graph using a spring force algorithm. + /*! + \nosubgrouping + */ + class UndirectedGraph : public Layout + { + /*! \name UndirectedGraph Constructor/Destructor *///------------------ + //@{ + public: + + //! UndirectedGraph constructor. + UndirectedGraph( ) : Layout( ), _center( "" ) { } + //@} + //--------------------------------------------------------------------- + + + + /*! \name Force Layout Generation Management *///---------------------- + //@{ + public: + + //! Layout 'graph' using a spring force algorithm. + virtual void layout( la::Graph& graph, la::Grid& grid, + QRectF r, utl::Progress& progress, int step = -1 ); + + static void add( VectorF& a, const VectorF& b ); + + static void scale( VectorF& p, float scale ); + + static VectorF vector( VectorF a, VectorF b ); + + static float length( const VectorF& v ); + + static float length2( const VectorF& v ); + + private: + + VectorF computeRepulseForce( la::Node& node, la::Node::Set& adjacentNodes, la::Node::Set& nodes, la::Graph& graph ); + + VectorF computeSpringForce( la::Node& node, la::Node::Set& adjacentNodes, la::Graph& graph ); + + la::Node _center; + + protected: + + static void computeBoundingBox( std::vector< VectorF >& positions, VectorF& min, VectorF& max ); + //@} + //--------------------------------------------------------------------- + }; + } // ::qan::la +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // laLayout_h + ============================================================ --- libs/qanava/src/la/laNode.cpp 41129452cf3dcd33b503e2c0a3af5d81abc40366 +++ libs/qanava/src/la/laNode.cpp 41129452cf3dcd33b503e2c0a3af5d81abc40366 @@ -0,0 +1,136 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laNode.cpp +// \author Benoit Autheman (address@hidden) +// \date 2004 February 15 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "./laNode.h" +#include "./laGraph.h" + + +// Std headers +#include +#include + + +namespace qan { // ::qan +namespace la { // ::qan::la + + +/* Node Constructor/Destructor *///-------------------------------------------- +Node::Node( const std::string& label ) +{ + initAttributes( 5 ); + setLabel( label ); + setType( -1 ); + VectorF v( 2 ); v( 0 ) = 0.f; v( 0 ) = 0.f; + setPosition( v ); + setDimension( v ); +} + +Node::Node( const std::string& label, int type ) +{ + initAttributes( 5 ); + setLabel( label ); + setType( type ); + VectorF v( 2 ); v( 0 ) = 0.f; v( 0 ) = 0.f; + setPosition( v ); + setDimension( v ); +} +//----------------------------------------------------------------------------- + + + +/* Node Edges Management *///-------------------------------------------------- +void Node::collectOutNodes( Node::List& outNodes ) +{ + for ( Edge::List::iterator outEdgeIter = _outEdges.begin( ); outEdgeIter != _outEdges.end( ); outEdgeIter++ ) + outNodes.push_back( &( ( *outEdgeIter )->getDst( ) ) ); +} + +void Node::collectInNodes( Node::List& inNodes ) +{ + for ( Edge::List::iterator intEdgeIter = _inEdges.begin( ); intEdgeIter != _inEdges.end( ); intEdgeIter++ ) + inNodes.push_back( &( ( *intEdgeIter )->getSrc( ) ) ); +} + +void Node::collectOutNodesSet( la::Node::Set& outNodes ) const +{ + // Add all edge destination to the out nodes set + const Edge::List& edges = getOutEdges( ); + Edge::List::const_iterator edgeIter = edges.begin( ); + for ( ; edgeIter != edges.end( ); edgeIter++ ) + outNodes.insert( &( *edgeIter )->getDst( ) ); +} + +void Node::collectInNodesSet( la::Node::Set& inNodes ) const +{ + // Add all edge destination to the out nodes set + const Edge::List& edges = getInEdges( ); + Edge::List::const_iterator edgeIter = edges.begin( ); + for ( ; edgeIter != edges.end( ); edgeIter++ ) + inNodes.insert( &( *edgeIter )->getSrc( ) ); +} + +void Node::getAdjacentNodesSet( la::Node::Set& adjacentNodes ) const +{ + Node::Set outNodes; collectOutNodesSet( outNodes ); + Node::Set inNodes; collectInNodesSet( inNodes ); + + std::set_union( outNodes.begin( ), outNodes.end( ), + inNodes.begin( ), inNodes.end( ), + std::insert_iterator< Node::Set >( adjacentNodes, adjacentNodes.begin( ) ) ); +} + +void Node::getNonAdjacentNodesSet( Node::Set& nonAdjacentNodes, const la::Graph& graph ) const +{ + Node::Set adjacentNodes; getAdjacentNodesSet( adjacentNodes ); + Node::Set graphNodes; graph.collectNodes( graphNodes ); + + std::set_difference( graphNodes.begin( ), graphNodes.end( ), + adjacentNodes.begin( ), adjacentNodes.end( ), + std::insert_iterator< Node::Set >( nonAdjacentNodes, nonAdjacentNodes.begin( ) ) ); + + // Remove the node idself from to non adjacent nodes list + nonAdjacentNodes.erase( const_cast< Node* >( this ) ); +} +//----------------------------------------------------------------------------- + + + +/* Node Attributes Management *///--------------------------------------------- +void Node::setDate( const std::string& date ) +{ + QDateTime dt = QDateTime::fromString( date.c_str( ), Qt::ISODate ); + if ( dt.isValid( ) ) + setAttribute< QDateTime >( Node::DATE, dt ); +} +//----------------------------------------------------------------------------- + + +} // ::qan::la +} // ::qan + ============================================================ --- libs/qanava/src/la/laNode.h 39795c963f6c9fa5a1bd71fa80818d1eaed2ec23 +++ libs/qanava/src/la/laNode.h 39795c963f6c9fa5a1bd71fa80818d1eaed2ec23 @@ -0,0 +1,273 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laNode.h +// \author Benoit Autheman (address@hidden) +// \date 2004 February 15 +//----------------------------------------------------------------------------- + + +#ifndef laNode_h +#define laNode_h + + +// Qanava headers +#include "./laEdge.h" +#include "./laVectorF.h" + + +// Standard headers +#include +#include +#include +#include +#include + + +// QT headers +#include + + +//----------------------------------------------------------------------------- +//! Root qanava namespace +namespace qan { // ::qan + //! Classes related to graph description and storage. + /*! 'la' originally stands for link analysis, the name has been kept even if the link analysis part has never + been shipped with the public version of Qanava. */ + namespace la { // ::qan::la + + class Graph; + + //! Model a node in a standard weighted and directed graph. + /*! + \nosubgrouping + */ + class Node + { + /*! \name Node Constructor/Destructor *///------------------------- + //@{ + public: + + //! Node constructor with label initialisation. + Node( const std::string& label ); + + //! Node constructor with label and type initialisation. + Node( const std::string& label, int type ); + + //! Node destructor. + ~Node( ) { } + + private: + + Node( const Node& n ); + //@} + //----------------------------------------------------------------- + + + + /*! \name Node Attributes Management *///-------------------------- + //@{ + public: + + template < typename T > + void addAttribute( T t ) + { + _attributes.push_back( new T( t ) ); + } + + template < typename T > + T* getAttribute( int role ) + { + assert( ( unsigned int )role < _attributes.size( ) ); + return ( _attributes[ role ] != 0 ? static_cast< T* >( _attributes[ role ] ) : 0 ); + } + + template < typename T > + const T* getAttribute( int role ) const + { + assert( ( unsigned int )role < _attributes.size( ) ); + return ( _attributes[ role ] != 0 ? static_cast< const T* >( _attributes[ role ] ) : 0 ); + } + + template < typename T > + void setAttribute( int role, const T& t ) + { + assert( role < ( int )_attributes.size( ) ); + if ( _attributes[ role ] == 0 ) + _attributes[ role ] = new T( t ); + else + *static_cast< T* >( _attributes[ role ] ) = t; + } + + void initAttributes( unsigned int attributeCount ) + { + if ( _attributes.size( ) < attributeCount ) // Add attributes to fit the requested attribute count + { + for ( unsigned int attribute = _attributes.size( ); attribute < attributeCount; attribute++ ) + _attributes.push_back( 0 ); + } + } + + private: + + std::vector< void* > _attributes; + //@} + //----------------------------------------------------------------- + + + + /*! \name Node Edges Management *///------------------------------- + //@{ + public: + + //! STL typedef for a list of la::Node. + typedef std::list< Node* > List; + + //! STL typedef for a set of la::Node. + typedef std::set< Node* > Set; + + //! Get a list of all nodes pointing to this node. + const Edge::List& getInEdges( ) const { return _inEdges; } + + //! Get a list of all nodes pointing to this node. + Edge::List& getInEdges( ) { return _inEdges; } + + //! Get a list of all node pointed by this node. + const Edge::List& getOutEdges( ) const { return _outEdges; } + + //! Get a list of all node pointed by this node. + Edge::List& getOutEdges( ) { return _outEdges; } + + //! Collect a list of this node sub nodes. + void collectOutNodes( Node::List& outNodes ); + + //! Collect a list of this node in nodes. + void collectInNodes( Node::List& outNodes ); + + //! Collect a set of unique nodes pointed by this node. + void collectOutNodesSet( Node::Set& outNodes ) const; + + //! Collect a set of unique nodes referencing this node. + void collectInNodesSet( Node::Set& nodes ) const; + + //! Add an in edge. + void addInEdge( Edge& edge ) { _inEdges.push_back( &edge ); } + + //! Add an out edge. + void addOutEdge( Edge& edge ) { _outEdges.push_back( &edge ); } + + //! Get node in degree. + unsigned int getInDegree( ) const { return _inEdges.size( ); } + + //! Get node out degree. + unsigned int getOutDegree( ) const { return _outEdges.size( ); } + + //! Get a list of nodes adjacent to this (all in and out nodes, without this). + void getAdjacentNodesSet( la::Node::Set& nodes ) const; + + //! Get a list of nodes non adjacent to this (all nodes minus the adjacent node set collected with getAdjacentNodesSet()). + void getNonAdjacentNodesSet( Node::Set& nonAdjacentNodes, const la::Graph& graph ) const; + + //! Return true if this node is a "leaf" (ie has no out edges). + bool isLeaf( ) const { return _outEdges.size( ) == 0; } + + private: + + //! Input edges. + Edge::List _inEdges; + + //! Output edges. + Edge::List _outEdges; + //@} + //----------------------------------------------------------------- + + + + /*! \name Node Property Management *///---------------------------- + //@{ + public: + + //! Attribute role. + enum Role + { + TYPE = 1, + LABEL = 2, + POSITION = 3, + DIMENSION = 4, + DATE = 5, + USER = 6 + }; + + enum { StdAttributeCount = 5 }; + + //! Get this node label. + const std::string& getLabel( ) const { return *getAttribute< std::string >( Node::LABEL ); } + + //! Set this node label. + void setLabel( const std::string& label ) { setAttribute< std::string >( Node::LABEL, label ); } + + //! Set this node's user defined type. + void setType( int type ) { setAttribute< int >( Node::TYPE, type ); } + + //! Get this node's user defined type. + int getType( ) const { return *getAttribute< int >( Node::TYPE ); } + + //! . + VectorF& getPosition( ) { return *getAttribute< VectorF >( Node::POSITION ); } + + //! . + const VectorF& getPosition( ) const { return *getAttribute< VectorF >( Node::POSITION ); } + + //! . + void setPosition( VectorF& position ) { setAttribute< VectorF >( Node::POSITION, position ); } + + //! . + void setPosition( float x, float y ) + { + VectorF& position = getPosition( ); + position( 0 ) = x; position( 1 ) = y; + } + + const VectorF& getDimension( ) const { return *getAttribute< VectorF >( Node::DIMENSION ); } + + void setDimension( const VectorF& dimension ) { setAttribute< VectorF >( Node::DIMENSION, dimension ); } + + void setDimension( float x, float y ) + { + VectorF& dimension = *getAttribute< VectorF >( Node::DIMENSION ); + dimension( 0 ) = x; dimension( 1 ) = y; + } + + //! Set the node date from a text string with the Posix Time format (ex: 2002-Jan-01 10:00:01). + void setDate( const std::string& date ); + + //! Return the node date under Posix Time format (0 if the date is undefined). + const QDateTime* getDate( ) const { return getAttribute< QDateTime >( Node::DATE ); } + //@} + //----------------------------------------------------------------- + }; + } // ::qan::la +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // laNode_h ============================================================ --- libs/qanava/src/la/laRepository.cpp 0aee16d368abe8b5066d29f4b73bb990ac548f42 +++ libs/qanava/src/la/laRepository.cpp 0aee16d368abe8b5066d29f4b73bb990ac548f42 @@ -0,0 +1,327 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laRepository.cpp +// \author Benoit Autheman (address@hidden) +// \date 2005 December 23 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "./laRepository.h" + + +// Standard headers +#include +#include +#include + + +// QT headers +#include + + +namespace qan { // ::qan +namespace la { // ::qan::la + + +/* Graph Serialization Management *///----------------------------------------- +void PajekRepository::load( Graph* graph ) +{ + std::ifstream netFile( getName( ).c_str( ) ); + if ( !netFile.is_open( ) ) + return; + + Mode mode = UNDEFINED; + while ( !netFile.eof( ) ) + { + std::string line; + std::getline( netFile, line ); // Parse the file line by line + + std::string header( "" ); + { + std::stringstream lineStream; + lineStream << line; + lineStream >> header; + } + + Mode oldMode = mode; + if ( header == "*Vertices" ) + mode = VERTICES; + else if ( header == "*Arcs" ) + mode = ARCS; + else if ( header == "*Edges" ) + mode = EDGES; + if ( oldMode != mode ) + continue; // A header line has just been read, jump to the next line + + std::stringstream lineStream; + lineStream << line; + + switch ( mode ) + { + case VERTICES: + { + int nodeId( -1 ); + lineStream >> nodeId; + + std::string nodeName( "" ); + lineStream >> nodeName; + + if ( ( nodeId > 0 ) && nodeName.size( ) > 0 ) + { + graph->insertNode( nodeName ); + } + } + break; + + case ARCS: + { + int nodeSrcId( -1 ); + lineStream >> nodeSrcId; + + int nodeDstId( -1 ); + lineStream >> nodeDstId; + + if ( nodeSrcId > 0 && nodeDstId > 0 ) + { + la::Node* nodeSrc = graph->findNode( nodeSrcId - 1 ); + la::Node* nodeDst = graph->findNode( nodeDstId - 1 ); + if ( nodeSrc != 0 && nodeDst != 0 ) + graph->createEdge( *nodeSrc, *nodeDst ); + } + } + break; + + case EDGES: + { + int nodeSrcId( -1 ); + lineStream >> nodeSrcId; + + int nodeDstId( -1 ); + lineStream >> nodeDstId; + + if ( nodeSrcId > 0 && nodeDstId > 0 ) + { + la::Node* nodeSrc = graph->findNode( nodeSrcId - 1 ); + la::Node* nodeDst = graph->findNode( nodeDstId - 1 ); + if ( nodeSrc != 0 && nodeDst != 0 ) + graph->createEdge( *nodeSrc, *nodeDst ); + } + } + break; + + case UNDEFINED: + default: + break; + } + } + netFile.close( ); + graph->generateRootNodes( ); +} + +void PajekRepository::save( Graph* graph ) +{ + +} +//----------------------------------------------------------------------------- + + +/* Graph Serialization Management *///----------------------------------------- +void GraphvizRepository::load( Graph* graph ) +{ + +} + +void GraphvizRepository::save( Graph* graph ) +{ + std::ofstream ofs; + ofs.open( getName( ).c_str( ) ); + if ( !ofs.is_open( ) ) + return; + + ofs << "graph g {\n"; + ofs << "\t center=true; \n"; + ofs << "#\t page=\"18,18\"; \n"; + ofs << "\t size=\"20,20\"; \n"; + ofs << "#\t ratio=compress; \n"; + ofs << "#\t concentrate=true; \n"; + ofs << "\t overlap=true; \n"; + ofs << "\t orientation=paysage; \n"; + + ofs << "\t node [ shape=box, style=filled, fontsize=10, height=0.2, width=0.4 ];\n"; + ofs << "\t edge [ len=1.5 ];\n"; + + // Dump nodes + Node::List::iterator nodeIter = graph->getNodes( ).begin( ); + for ( int n = 0; nodeIter != graph->getNodes( ).end( ); nodeIter++ ) + { + Node* node = *nodeIter; + ofs << "\t" << n++/*node->getId( )*/ << " [label=\"" << node->getLabel( ).c_str( ) << "\"];\n"; + } + + // Dump nodes edges + for ( nodeIter = graph->getNodes( ).begin( ); nodeIter != graph->getNodes( ).end( ); nodeIter++ ) + { + Node* node = *nodeIter; + const Edge::List& edges = node->getOutEdges( ); + Edge::List::const_iterator edgeIter = edges.begin( ); + for ( ; edgeIter != edges.end( ); edgeIter++ ) + { + //Edge* edge = *edgeIter; + ofs << "\t" << 0/*edge->getSrc( ).getId( )*/ << " -- " << 0/*edge->getDst( ).getId( )*/ << "\n"; + } + } + ofs << "}\n"; + ofs.close( ); +} +//----------------------------------------------------------------------------- + + +/* GML Graph Serialization Management *///------------------------------------- +GMLRepository::GMLRepository( const std::string& name ) : + Repository( name ) +{ + +} + +void GMLRepository::load( Graph* graph ) +{ + if ( getName( ).size( ) <= 0 ) + return; + + QFile file( getName( ).c_str( ) ); + if ( !file.open( QFile::ReadOnly | QFile::Text ) ) + return; + + QString errorStr( "" ); + int errorLine = -1; + int errorColumn = -1; + + QDomDocument domDocument; + if ( !domDocument.setContent( &file, true, &errorStr, &errorLine, &errorColumn ) ) + return; + + QDomElement root = domDocument.documentElement( ); + if ( root.tagName( ) != "graphml" ) + return; + + QDomElement graphChild = root.firstChildElement( "graph" ); + if ( !graphChild.isNull( ) ) + parseGraph( domDocument, graphChild, graph ); +} + +void GMLRepository::parseGraph( QDomDocument domDocument, QDomElement element, Graph* graph ) +{ + if ( element.tagName( ) != "graph" ) + return; + + // Parse nodes + QDomNodeList nodes = element.elementsByTagName( "node" ); + for( unsigned int n = 0; n < nodes.length( ); n++ ) + { + QDomElement node = nodes.item( n ).toElement( ); + if ( node.isNull( ) ) + continue; + QString nodeId = node.attribute( "id" ); + la::Node* laNode = graph->insertNode( nodeId.toStdString( ) ); + + + // Parse data elements + QDomNodeList dataNodes = node.elementsByTagName( "data" ); + for ( unsigned int dn = 0; dn < dataNodes.length( ); dn++ ) + { + QDomElement dataNode = dataNodes.item( dn ).toElement( ); + if ( dataNode.isNull( ) ) + continue; + + QString dataKey = dataNode.attribute( "key" ); + QString dataText = dataNode.text( ); + + if ( dataKey.length( ) <= 0 ) + continue; + + if ( graph->hasAttribute( dataKey.toStdString( ) ) == -1 ) + graph->addAttribute< std::string >( dataKey.toStdString( ), std::string( "" ) ); + std::string stdDataKey( dataKey.toStdString( ) ); + std::string stdDataText( dataText.toStdString( ) ); + + graph->setAttribute< std::string >( laNode, stdDataKey, stdDataText ); + } + } + + graph->generateRootNodes( ); + + //return; + // Parse edges + QDomNodeList edges = element.elementsByTagName( "edge" ); + for( unsigned int e = 0; e < edges.length( ); e++ ) + { + QDomElement edge = edges.item( e ).toElement( ); + if ( edge.isNull( ) ) + continue; + QString edgeSource = edge.attribute( "source" ); + QString edgeTarget = edge.attribute( "target" ); + + + // Parse data elements + double weight = 0.; + QDomNodeList dataNodes = edge.elementsByTagName( "data" ); + for ( unsigned int dn = 0; dn < dataNodes.length( ); dn++ ) + { + QDomElement dataNode = dataNodes.item( dn ).toElement( ); + if ( dataNode.isNull( ) ) + continue; + + QString dataKey = dataNode.attribute( "key" ); + QString dataText = dataNode.text( ); + + if ( dataKey.length( ) <= 0 ) + continue; + + if ( dataKey == "weight" ) + weight = dataText.toDouble( ); + } + + if ( ( edgeSource.length( ) > 0 ) && ( edgeTarget.length( ) > 0 ) ) + { + la::Node* laSrc = graph->findNode( edgeSource.toStdString( ) ); + la::Node* laDst = graph->findNode( edgeTarget.toStdString( ) ); + if ( ( laSrc != 0 ) && ( laDst != 0 ) ) + graph->createEdge( *laSrc, *laDst, weight ); + } + //break; + } + + graph->generateRootNodes( ); +} + +void GMLRepository::save( Graph* graph ) +{ + +} +//----------------------------------------------------------------------------- + + +} // ::qan::la +} // ::qan + ============================================================ --- libs/qanava/src/la/laRepository.h d8dc9c74947562f09270d3d56fb3929bc1bc7027 +++ libs/qanava/src/la/laRepository.h d8dc9c74947562f09270d3d56fb3929bc1bc7027 @@ -0,0 +1,176 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laRepository.h +// \author Benoit Autheman (address@hidden) +// \date 2005 December 23 +//----------------------------------------------------------------------------- + + +#ifndef laRepository_h +#define laRepository_h + + +// Qanava headers +#include "../../src/utl/utlConfig.h" +#include "../../src/la/laGraph.h" + + +// STD headers +#include + + +// QT headers +#include + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan + namespace la { // ::qan::la + + //! Model an abstract storage object for graphs. + /*! + \nosubgrouping + */ + class Repository + { + /*! \name Graph Serialization Management *///---------------------- + //@{ + public: + + //! Repository constructor with name initialization. + Repository( const std::string& name ) : _name( name ) { } + + //! Repsoitory standard virtual destructor. + virtual ~Repository( ) { } + + //! . + virtual void load( Graph* graph ) = 0; + + //! . + virtual void save( Graph* graph ) = 0; + + //! Get the repository name. + const std::string& getName( ) const { return _name; } + + private: + + //! Repository name (usually a file name). + std::string _name; + //@} + //----------------------------------------------------------------- + }; + + + + //! + /*! + \nosubgrouping + */ + class PajekRepository : public la::Repository + { + /*! \name Graph Serialization Management *///---------------------- + //@{ + public: + + PajekRepository( const std::string& name ) : Repository( name ) { } + + virtual ~PajekRepository( ) { } + + //! . + virtual void load( Graph* graph ); + + //! . + virtual void save( Graph* graph ); + + private: + + //! Current data mode (Pajek Vertices, Arcs or Edges) + enum Mode + { + UNDEFINED = 1, + VERTICES = 2, + ARCS = 4, + EDGES = 8 + }; + //@} + //----------------------------------------------------------------- + }; + + + + //! DEPRECATED + /*! DEPRECATED, used for debugging purposes only. + \nosubgrouping + */ + class GraphvizRepository : public la::Repository + { + /*! \name Graph Serialization Management *///---------------------- + //@{ + public: + + GraphvizRepository( const std::string& name ) : Repository( name ) { } + + virtual ~GraphvizRepository( ) { } + + //! . + virtual void load( Graph* graph ); + + //! . + virtual void save( Graph* graph ); + //@} + //----------------------------------------------------------------- + }; + + //! GML (XML based Graph Markup Language) repository. + /*! + \nosubgrouping + */ + class GMLRepository : public la::Repository + { + /*! \name Graph Serialization Management *///---------------------- + //@{ + public: + + GMLRepository( const std::string& name ); + + virtual ~GMLRepository( ) { } + + //! . + virtual void load( Graph* graph ); + + //! . + virtual void save( Graph* graph ); + + private: + + void parseGraph( QDomDocument domDocument, QDomElement graphChild, Graph* graph ); + //@} + //----------------------------------------------------------------- + }; + } // ::qan::la +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // laGraphVisitor_h + ============================================================ --- libs/qanava/src/la/laTimeTree.cpp f1c5adc6b822976aaf94269507841747570d8b96 +++ libs/qanava/src/la/laTimeTree.cpp f1c5adc6b822976aaf94269507841747570d8b96 @@ -0,0 +1,630 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laLayout.cpp +// \author Benoit Autheman (address@hidden) +// \date 2004 December 05 +//----------------------------------------------------------------------------- + + +// Qanava haders +#include "./laTimeTree.h" + + +// Std headers +#include + + +namespace qan { // ::qan +namespace la { // ::qan::la + + +bool TimeTree::NodeDateComp::operator()( const Node* n1, const Node* n2 ) const +{ + const QDateTime* d1 = n1->getDate( ); + const QDateTime* d2 = n2->getDate( ); + if ( d1 == 0 || d2 == 0 ) + return false; + return ( *d1 < *d2 ); +} + +/* TimeTree Grid Management *///----------------------------------------------- +/*! + \param cy Y coordinate of the cluster top left corner + \param w Width of the cluster. + \param h Height of the cluster. + */ +void TimeTree::GridBuilder::buildClusterGrid( int cy, int w, int h, int r, int g, int b ) +{ + _grid.addLine( QLineF( 0, cy + h, w, cy + h ), 1, false, false ); + _grid.addRectangle( QRectF( 0, cy, w, h + 1 ), QColor( r, g, b ) ); +} + +/*! + \param sortedNodes Set of time sorted nodes already placed on the canvas. + \param maxX, maxY Maximum coordinate for the nodes in the current layout. +*/ +void TimeTree::GridBuilder::buildTimeGrid( NodeSet& nodes, int, int height ) +{ + // Draw vertical time grid lines + float x = 10.f; + const QDateTime* lastNodeDate = 0; + for ( NodeSet::iterator nodeIter = nodes.begin( ); nodeIter != nodes.end( ); nodeIter++ ) + { + // Set default separation line settings + bool dash = false; + bool dot = true; + + const QDateTime* nodeDate = ( *nodeIter )->getDate( ); + if ( nodeDate != 0 && lastNodeDate != 0 && ( *nodeDate == *lastNodeDate ) ) + x -= incX; + + // Different days are separated with a strong line + if ( ( nodeDate != 0 && lastNodeDate == 0 ) || // First day + ( nodeDate != 0 && lastNodeDate != 0 && ( nodeDate->date( ) > lastNodeDate->date( ) ) ) ) // New Day + { + dash = true; + dot = false; + + // Add the date text + std::string dateText( "" ); + try + { + //dateText = nodeDate->date( ).toString( "yyyy-MMM-dd" ).latin1( ); + dateText = std::string( nodeDate->date( ).toString( "yyyy-MMM-dd" ).toAscii( ) ); + } catch( std::exception& ) { } + _grid.addText( dateText, QPointF( ( int )x, 2 ), true ); + _grid.addText( dateText, QPointF( ( int )x, height - 17 ), true ); + } + + // Add separation line to grid + _grid.addLine( QLineF( ( int )x - 5, 0, ( int )x - 5, height ), 1, dash, dot ); + + lastNodeDate = nodeDate; + x += incX; + } +} + +void TimeTree::GridBuilder::buildTimeLabel( Node& node, int x, int y ) +{ + const QDateTime* nodeDate = node.getDate( ); + if ( nodeDate != 0 ) + { + // Add date label to grid + std::string timeText( "" ); + try + { + timeText = std::string( nodeDate->toString( QString( "hh:mm::ss" ) ).toAscii( ) ); + } catch( std::exception& ) { timeText = "00:01:00"; } + _grid.addText( timeText, QPointF( x, y ) ); + } +} +//----------------------------------------------------------------------------- + +bool TimeTree::Group::GroupMedDateComp::operator()( const Group* g1, const Group* g2 ) const +{ + QDateTime tg1 = g1->getMedianDate( ); + QDateTime tg2 = g2->getMedianDate( ); + return ( tg1 < tg2 ); +} + +/*! + \return A pointer to the line node list, 0 if line index is negative or superior to the group lines count. + */ +la::Node::List* TimeTree::Group::getLine( unsigned int line ) +{ + if ( line >= _lines.size( ) ) + return 0; + return _lines[ line ]; +} + +void TimeTree::Group::collectNodes( la::Node::List& nodes ) const +{ + for ( Lines::const_iterator lineIter = _lines.begin( ); lineIter != _lines.end( ); lineIter++ ) + { + const la::Node::List* lineNodes = *lineIter; + std::copy( lineNodes->begin( ), lineNodes->end( ), + std::back_insert_iterator< la::Node::List >( nodes ) ); + } +} + +void TimeTree::Group::setNodesType( int type ) +{ + la::Node::List nodes; + collectNodes( nodes ); + for ( la::Node::List::iterator nodeIter = nodes.begin( ); nodeIter != nodes.end( ); nodeIter++ ) + ( *nodeIter )->setType( type ); +} + +/*! + To avoid aggressive merge during layout, the method return true when a node with no date + occurs. + */ +bool TimeTree::Group::intersect( const Group& group ) const +{ + for ( Lines::const_iterator lineIter = _lines.begin( ); lineIter != _lines.end( ); lineIter++ ) + { + const la::Node::List* lineNodes = *lineIter; + if ( lineNodes->size( ) < 1 ) + continue; + const la::Node* nodeFirst = lineNodes->front( ); + const la::Node* nodeLast = lineNodes->back( ); + + const QDateTime* nodeFirstDate = nodeFirst->getDate( ); + const QDateTime* nodeLastDate = nodeLast->getDate( ); + if ( nodeFirstDate == 0 || nodeLastDate == 0 ) + continue; + + // Test the current line time interval with the given group ones + for ( Lines::const_iterator lineDstIter = group._lines.begin( ); lineDstIter != group._lines.end( ); lineDstIter++ ) + { + const la::Node::List* lineDstNodes = *lineDstIter; + if ( lineDstNodes->size( ) < 1 ) + continue; + const la::Node* nodeDstFirst = lineDstNodes->front( ); + const la::Node* nodeDstLast = lineDstNodes->back( ); + + const QDateTime* nodeDstFirstDate = nodeDstFirst->getDate( ); + const QDateTime* nodeDstLastDate = nodeDstLast->getDate( ); + if ( nodeDstFirstDate == 0 || nodeDstLastDate == 0 ) + continue; + + // Test mutual intersection + + // Dst node area has an extremity in the node area + if ( ( ( *nodeDstFirstDate >= *nodeFirstDate ) && ( *nodeDstFirstDate <= *nodeLastDate ) ) || + ( ( *nodeDstLastDate >= *nodeFirstDate ) && ( *nodeDstLastDate <= *nodeLastDate ) ) ) + return true; + + // Dst node area is larger than the node are + if ( ( *nodeDstFirstDate <= *nodeFirstDate ) && ( *nodeDstLastDate >= *nodeLastDate ) ) + return true; + } + } + return false; +} + +QDateTime TimeTree::Group::getMedianDate( ) const +{ + la::Node::List groupNodes; + collectNodes( groupNodes ); + + // Get the min and max date in the cluster articles + QDateTime dateMin( QDate( 3000, 1, 1 ), QTime( 0, 0 ) ); + QDateTime dateMax( QDate( 0, 1, 1 ), QTime( 0, 0 ) ); + for ( la::Node::List::const_iterator nodeIter = groupNodes.begin( ); nodeIter != groupNodes.end( ); nodeIter++ ) + { + const QDateTime* nodeDate = ( *nodeIter )->getDate( ); + if ( nodeDate != 0 ) + { + if ( *nodeDate < dateMin ) + dateMin = *nodeDate; + if ( *nodeDate > dateMax ) + dateMax = *nodeDate; + } + } + + // Get the median time + //time_duration groupDuration = dateMax - dateMin; + //return dateMin + ( groupDuration / 2 ); + int dayToMedian = dateMin.daysTo( dateMax ) / 2; + QDateTime result = dateMin.addDays( dayToMedian ); + // BUG: prendre l'heure en compte et pas seulement les days + return result; +} + + +/*! + This method assumer that the groups inside the two track are disjoint within their own track groups. + */ +bool TimeTree::Track::isDisjointOf( Track& track ) +{ + // Check that given track groups are disjoint from thie track groups + Group::Groups::iterator groupIter = track.getGroups( ).begin( ); + for ( ; groupIter != track.getGroups( ).end( ); groupIter++ ) + { + Group::Groups::iterator groupDstIter = getGroups( ).begin( ); + for ( ; groupDstIter != getGroups( ).end( ); groupDstIter++ ) + { + if ( ( *groupIter )->intersect( **groupDstIter ) ) + return false; + } + } + return true; +} + +/*! This method will merge tracks even if they have intersecting groups, so please verfiy track intersection if + such behaviour is not desired. + */ +void TimeTree::Track::mergeTrack( Track& track ) +{ + Group::Groups& trackGroups = track.getGroups( ); + for ( Group::Groups::iterator groupIter = trackGroups.begin( ); groupIter != trackGroups.end( ); groupIter++ ) + _groups.push_front( *groupIter ); + trackGroups.clear( ); +} + +/*! + \return Maximum number of lines in all track node groups, 0 if there is no lines. + */ +int TimeTree::Track::getLineCount( ) const +{ + int lineCount = 0; + for ( Group::Groups::const_iterator groupIter = _groups.begin( ); groupIter != _groups.end( ); groupIter++ ) + { + if ( ( *groupIter )->getLineCount( ) > lineCount ) + lineCount = ( *groupIter )->getLineCount( ); + } + return lineCount; +} + +/*! + \return Height of the track after the layout. + */ +float TimeTree::Track::layout( float trackY, float width, GridBuilder& gridBuilder ) +{ + float trackYStart = trackY; + trackY += trackIntervalY; + int lineCount = getLineCount( ); + for ( int line = 0; line < lineCount; line++ ) + { + la::Node::List lineNodes; + + // Regroup track group current line as one line + for ( Group::Groups::iterator groupIter = getGroups( ).begin( ); groupIter != getGroups( ).end( ); groupIter++ ) + { + la::Node::List* groupLineNodes = ( *groupIter )->getLine( line ); + if ( groupLineNodes == 0 ) + continue; + std::copy( groupLineNodes->begin( ), groupLineNodes->end( ), + std::back_insert_iterator< la::Node::List >( lineNodes ) ); + } + + // Get current line maximum height + float lineHeight = 0.f; + for ( la::Node::List::iterator lineNodeIter = lineNodes.begin( ); lineNodeIter != lineNodes.end( ); lineNodeIter++ ) + { + la::Node* lineNode = ( *lineNodeIter ); + if ( lineNode->getDimension( )( 1 ) > lineHeight ) + lineHeight = lineNode->getDimension( )( 1 ); + } + + // Center line nodes vertically + for ( la::Node::List::iterator lineNodeIter = lineNodes.begin( ); lineNodeIter != lineNodes.end( ); lineNodeIter++ ) + { + la::Node* lineNode = ( *lineNodeIter ); + gridBuilder.buildTimeLabel( *lineNode, ( int )lineNode->getPosition( )( 0 ), ( int )trackY - 15 ); + float deltaY = ( ( lineHeight - lineNode->getDimension( )( 1 ) ) / 2.f ); + lineNode->getPosition( )( 1 ) = trackY + deltaY; + } + + // Switch to next line + trackY += lineHeight; + if ( line < lineCount - 1 ) + { + trackY += 2; + + // Add line grid separation line + gridBuilder.getGrid( ).addLine( QLineF( 0, ( int )trackY, ( int )width, ( int )trackY ), 1, false, true ); + + trackY += lineIntervalY; + } + } + trackY += 2; + return ( trackY - trackYStart ); +} + +void TimeTree::Track::collectGroups( Group::Groups& groups ) +{ + // Sort this track groups according to their average date thanks to a sorted multiset + Group::GroupSet groupSet; + std::copy( _groups.begin( ), _groups.end( ), std::inserter( groupSet, groupSet.begin( ) ) ); + + // Copy the sorted groups to the groups collection list + std::copy( groupSet.begin( ), groupSet.end( ), std::back_insert_iterator< Group::Groups >( groups ) ); +} + +int TimeTree::Track::getNodeCount( ) const +{ + int nodeCount = 0; + Group::Groups::const_iterator groupIter = _groups.begin( ); + for ( ; groupIter != _groups.end( ); groupIter++ ) + { + la::Node::List nodes; + ( *groupIter )->collectNodes( nodes ); + nodeCount += nodes.size( ); + nodes.clear( ); + } + return nodeCount; +} + +void TimeTree::Tracks::addTrack( Track* track ) +{ + _tracks.push_back( track ); +} + +void TimeTree::Tracks::mergeTracks( ) +{ + std::set< Track* > tracksMerged; + + // Try to insert each tracks in the other ones + for ( Track::Tracks::iterator trackIter = _tracks.begin( ); trackIter != _tracks.end( ); trackIter++ ) + { + Track* track = *trackIter; + + Track::Tracks::iterator trackDstIter = _tracks.begin( ); + for ( ; trackDstIter != _tracks.end( ); trackDstIter++ ) + { + Track* trackDst = *trackDstIter; + if ( track == trackDst ) + continue; + + // Don't merge to a track that is merged and no longer exists + if ( tracksMerged.find( trackDst ) != tracksMerged.end( ) ) + continue; + + // Test if track content can be merged in dst track + if ( trackDst->isDisjointOf( *track ) ) + { + trackDst->mergeTrack( *track ); + tracksMerged.insert( track ); + } + } + } + + // Supress merged tracks + { + std::set< Track* >::iterator trackIter = tracksMerged.begin( ); + for ( ; trackIter != tracksMerged.end( ); trackIter++ ) + _tracks.remove( *trackIter ); + } +} + +/*! + \return Height of the resulting layout. + */ +float TimeTree::Tracks::layout( float width, GridBuilder& gridBuilder ) +{ + // Try to insert each tracks in the other ones + float trackY = 0.f; + unsigned int trackId = 0; + for ( Track::Tracks::iterator trackIter = _tracks.begin( ); trackIter != _tracks.end( ); trackId++, trackIter++ ) + { + Track* track = *trackIter; + + // For the first cluster increase space for the top days labels + float trackStart = trackY; + if ( trackId == 0 ) + trackY += trackIntervalY + 2; + + // Layout track groups + float height = track->layout( trackY, width, gridBuilder ); + trackY += height; + + int r = ( trackId % 2 == 0 ) ? 105 : 170; + int g = ( trackId % 2 == 0 ) ? 105 : 171; + int b = ( trackId % 2 == 0 ) ? 175 : 205; + + // For the last cluster increase space for the top days labels + if ( trackId >= _tracks.size( ) - 1 ) + trackY += trackIntervalY + 2; + float trackEnd = trackY; + + gridBuilder.buildClusterGrid( ( int )trackStart, ( int )width, ( int )( trackEnd - trackStart ), r, g, b ); + } + return trackY; +} + +void TimeTree::Tracks::collectGroups( Group::Groups& groups ) +{ + // Collect tracks in their natural order (in fact they are garanteed to be sorted as they have been + // added (and they have been added according to their group average date) + for ( Track::Tracks::iterator trackIter = _tracks.begin( ); trackIter != _tracks.end( ); trackIter++ ) + ( *trackIter )->collectGroups( groups ); +} + + +bool TimeTree::TrackDensityComp::operator()( const TimeTree::Track* t1, const TimeTree::Track* t2 ) const +{ + + return ( t1->getNodeCount( ) / t1->getLineCount( ) ) > ( t2->getNodeCount( ) / t2->getLineCount( ) ); +} + + +void TimeTree::Tracks::sortByNodeDensity( ) +{ + std::set< TimeTree::Track*, TrackDensityComp > tracksSetDensity; + std::copy( _tracks.begin( ), _tracks.end( ), std::inserter( tracksSetDensity, tracksSetDensity.begin( ) ) ); + _tracks.clear( ); + std::copy( tracksSetDensity.begin( ), tracksSetDensity.end( ), + std::back_insert_iterator< Track::Tracks >( _tracks ) ); +} + +// Layout settings +float TimeTree::incX = 83.f; + +float TimeTree::lineIntervalY = 16.f; + +float TimeTree::trackIntervalY = 16.f; + + +/* TimeTree Layout Generation Management *///---------------------------------- +/*! + \note If cluster track merge option is enabled, then a valid style manager must + have been provided in the TimeTree object constructor, otherwise, consecutive groups (clusters) + will eventually be affected the same graphic style, creating undiscernable groups. + */ +void TimeTree::layout( la::Graph& graph, Grid& grid, int /*width*/, int /*height*/, utl::Progress& /*progress*/ ) +{ + // Layout the nodes horizontally + NodeSet nodes; + std::copy( graph.getNodes( ).begin( ), graph.getNodes( ).end( ), + std::inserter( nodes, nodes.begin( ) ) ); + float layoutWidth = layoutNodesX( nodes ); + + // Generate groups for all nodes set to layout + Group::GroupSet groups; + NodeSetManager::iterator nodeSetIter = _nodeSetManager.begin( ); + for ( ; nodeSetIter != _nodeSetManager.end( ); nodeSetIter++ ) + { + Group* clusterGroup = buildGroup( **nodeSetIter ); + groups.insert( clusterGroup ); + } + + // Create a track per group (tracks are sorted by time, since groups already are) + Tracks* tracks = new Tracks( ); + for ( Group::GroupSet::iterator groupIter = groups.begin( ); groupIter != groups.end( ); groupIter++ ) + { + Track* track = new Track( ); + track->addGroup( *groupIter ); + tracks->addTrack( track ); + } + + // Optimize tracks placement + tracks->mergeTracks( ); + + // Sort tracks per average node density (to maximize node count on first page) +// tracks->sortByNodeDensity( ); + + // Affect styles such that two consecutive groups on a track do not have the same style + { + int groupId = 0; + Group::Groups groups; + tracks->collectGroups( groups ); + for ( Group::Groups::iterator groupIter = groups.begin( ); groupIter != groups.end( ); groupId++, groupIter++ ) + ( *groupIter )->setNodesType( 1 + ( groupId % 3 ) ); + } + + // Fix the tracks layout, ie assign concrete coordinate to graph nodes + GridBuilder gridBuilder( grid ); + float layoutHeight = tracks->layout( layoutWidth, gridBuilder ); + + // Draw the time grid + gridBuilder.buildTimeGrid( nodes, ( int )layoutWidth, ( int )layoutHeight ); +} + +float TimeTree::layoutNodesX( NodeSet& nodes ) +{ + // Set nodes horizontal (x) position according to their date + float x = 10.f; + Node* lastNode = 0; + for ( NodeSet::iterator sortedNodeIter = nodes.begin( ); sortedNodeIter != nodes.end( ); sortedNodeIter++ ) + { + Node* node = *sortedNodeIter; + if ( lastNode != 0 ) + { + const QDateTime* nodeDate = node->getDate( ); + const QDateTime* lastNodeDate = lastNode->getDate( ); + if ( nodeDate != 0 && lastNodeDate != 0 && ( *nodeDate == *lastNodeDate ) ) + x -= incX; + } + + node->setPosition( x, -1.0f ); // y=-1 used later to indicate the node as still not been placed + x += incX; + + lastNode = node; + } + return x; +} + +TimeTree::Group* TimeTree::buildGroup( NodeSet& clusterNodes ) +{ + Group* clusterGroup = new Group( ); + + la::Node::List nodes; + std::copy( clusterNodes.begin( ), clusterNodes.end( ), + std::back_insert_iterator< la::Node::List >( nodes ) ); + + // Consume all nodes, ie affect all nodes to a line + unsigned int runCount = 0; + while ( ( nodes.size( ) > 0 ) && ( runCount < clusterNodes.size( ) ) ) + { + // Consume as many nodes as possible for a line (ie all non simultaneous nodes or a node with a subnode in this cluster) + la::Node::List* lineNodes = new la::Node::List( ); + la::Node* prevNode = 0; + for ( la::Node::List::iterator nodeIter = nodes.begin( ); nodeIter != nodes.end( ); nodeIter++ ) + { + la::Node* node = *nodeIter; + + // Detect if the node hasn't already been positionned (ex: it is a sub node of an existing node in this cluster) + if ( node->getPosition( )( 1 ) >= 0.f ) + continue; + + if ( ( prevNode == 0 ) || + ( prevNode != 0 && ( node->getPosition( )( 0 ) > prevNode->getPosition( )( 0 ) ) ) ) + { + // Consume the node + lineNodes->push_back( node ); + node->getPosition( )( 1 ) = 1.0f; + prevNode = node; + + // Consume the node subnodes (and sort subnodes by date) + NodeSet sortedOutNodes; + la::Node::Set outNodes; node->collectOutNodesSet( outNodes ); + std::copy( outNodes.begin( ), outNodes.end( ), std::inserter( sortedOutNodes, sortedOutNodes.begin( ) ) ); + + for ( NodeSet::iterator outNodeIter = sortedOutNodes.begin( ); outNodeIter != sortedOutNodes.end( ); outNodeIter++ ) + { + la::Node* outNode = *outNodeIter; + if ( clusterNodes.find( outNode ) == clusterNodes.end( ) ) + continue; // Dismiss nodes not in this cluster (is not in the cluster sorted nodes set) + + if ( outNode->getPosition( )( 1 ) >= 0.f ) + continue; + + // Test that a node with a previous same date is not already in this line. Ex: Two sub + // articles have the same date, so the same x position, they must be on different lines. + bool skipNode = false; + la::Node::List::iterator lineNodeIter = lineNodes->begin( ); + for ( ; lineNodeIter != lineNodes->end( ); lineNodeIter++ ) + { + if ( outNode->getPosition( )( 0 ) == ( *lineNodeIter )->getPosition( )( 0 ) ) + skipNode = true; + } + if ( skipNode ) + continue; + + lineNodes->push_back( outNode ); + outNode->getPosition( )( 1 ) = 1.0f; + prevNode = outNode; + } + } + } + + // Supress all line nodes + for ( la::Node::List::iterator lineNodeIter = lineNodes->begin( ); lineNodeIter != lineNodes->end( ); lineNodeIter++ ) + nodes.remove( *lineNodeIter ); + + clusterGroup->addLine( lineNodes ); + + // Avoid infinite recursion, allow no more runs than there is nodes + runCount++; + } + + return clusterGroup; +} +//----------------------------------------------------------------------------- + + +} // ::qan::la +} // ::qan + ============================================================ --- libs/qanava/src/la/laTimeTree.h 1c33e3eef71fccd26284041f71be2b57d58034af +++ libs/qanava/src/la/laTimeTree.h 1c33e3eef71fccd26284041f71be2b57d58034af @@ -0,0 +1,294 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laTimeTree.h +// \author Benoit Autheman (address@hidden) +// \date 2004 December 05 +//----------------------------------------------------------------------------- + + +#ifndef laTimeTree_h +#define laTimeTree_h + + +// UTL headers +#include "../utl/utlManager.h" +#include "../utl/utlProgress.h" + + +// Qanava headers +#include "laLayout.h" +#include "laGrid.h" + + +//----------------------------------------------------------------------------- +namespace qan { // ::qan + namespace la { // ::qan::la + + //! Layout a graph in space taking into account group membership (clusters) and respecting a chronological order. + /*! + + Qanava timetree sample + + \nosubgrouping + */ + class TimeTree : public Layout + { + public: + + //! Sort nodes on the basis of their date (older first). + struct NodeDateComp + { + bool operator()( const Node* n1, const Node* n2 ) const; + }; + + //! STL set sorting node by date. + typedef std::multiset< la::Node*, NodeDateComp > NodeSet; + + //! Manager of NodeSet objects. + typedef utl::Manager< NodeSet > NodeSetManager; + + protected: + + //! Construct the grid for a cluster based time tree graph layout. + /*! + \nosubgrouping + */ + class GridBuilder + { + /*! \name TimeTree Grid Management *///---------------------------- + //@{ + public: + + //! . + GridBuilder( la::Grid& grid ) : _grid( grid ) { } + + public: + + //! Add _one_ grid element for a given cluster coordinates. + void buildClusterGrid( int cy, int w, int h, int r, int g, int b ); + + //! Add all horizontal time grid elements for the given (sorted) nodes. + void buildTimeGrid( NodeSet& nodes, int width, int height ); + + //! . + void buildTimeLabel( Node& node, int x, int y ); + + //! . + Grid& getGrid( ) { return _grid; } + + private: + + //! . + Grid& _grid; + //@} + //----------------------------------------------------------------- + }; + + public: + + //! Models a group of nodes in the same track (usually a group equals a cluster of nodes). + /*! + \nosubgrouping + */ + class Group + { + private: + + class GroupMedDateComp + { + public: + bool operator()( const Group* g1, const Group* g2 ) const; + }; + + public: + + //! . + Group( ) { } + + //! . + ~Group( ) { } + + //! Add a group of nodes corresponding to a line of nodes for a given cluster. + /*! The node must be sorted by date ascending order. */ + void addLine( la::Node::List* lineNodes ) { _lines.push_back( lineNodes ); } + + //! Get the number of lines in this group. + int getLineCount( ) const { return _lines.size( ); } + + //! Get the ith line in this group. + la::Node::List* getLine( unsigned int line ); + + //! Collect this group nodes to a given node list (list can be non emtpy). + void collectNodes( la::Node::List& nodes ) const; + + //! Affect a given style type to all of this group nodes. + void setNodesType( int type ); + + //! Test if a group intersect with this group time interval. + bool intersect( const Group& group ) const; + + //! Get this group median date. + QDateTime getMedianDate( ) const; + + typedef std::list< Group* > Groups; + + typedef std::vector< la::Node::List* > Lines; + + //! STL multi set with median date group sorting. + typedef std::multiset< Group*, GroupMedDateComp > GroupSet; + + protected: + + //! Nodes in each lines must be stored in . + Lines _lines; + }; + + + protected: + + //! Models a line of related groups of nodes (the track form a line, but the group in the track can take ultiple single lines). + /*! + \nosubgrouping + */ + class Track + { + public: + + Track( ) { } + + void addGroup( Group* group ) { _groups.push_back( group ); } + + //! Test if a given track time duration interval is disjoint from this track own duration. + bool isDisjointOf( Track& track ); + + //! Merge a given track groups to this track. + void mergeTrack( Track& track ); + + typedef std::list< Track* > Tracks; + + int getLineCount( ) const; + + float layout( float trackY, float width, GridBuilder& gridBuilder ); + + //! Collect groups in this track sorted by group's average date. + void collectGroups( Group::Groups& groups ); + + Group::Groups& getGroups( ) { return _groups; } + + int getNodeCount( ) const; + + protected: + + private: + + Group::Groups _groups; + }; + + + //! Sort tracks on the basis of their node (spatial) density. + struct TrackDensityComp + { + bool operator()( const Track* t1, const Track* t2 ) const; + }; + + + //! Model a series of tracks. + /*! + \nosubgrouping + */ + class Tracks + { + public: + + Tracks( ) { } + + void addTrack( Track* track ); + + void mergeTracks( ); + + float layout( float width, GridBuilder& gridBuilder ); + + //! Collect all tracks group to a group list in the left-right top to bottom order. + void collectGroups( Group::Groups& groups ); + + void sortByNodeDensity( ); + + protected: + + Track::Tracks _tracks; + }; + + + /*! \name TimeTree Constructor/Destructor *///------------------------- + //@{ + public: + + //! TimeTree constructor. + TimeTree( NodeSetManager& nodeSetManager ) : + Layout( ), + _nodeSetManager( nodeSetManager ) { } + + ~TimeTree( ) + { + + } + + private: + + //! . + NodeSetManager& _nodeSetManager; + //@} + //--------------------------------------------------------------------- + + + + /*! \name TimeTree Layout Generation Management *///------------------- + //@{ + public: + + static float incX; + + static float lineIntervalY; + + static float trackIntervalY; + + //! . + virtual void layout( la::Graph& graph, la::Grid& grid, int width, int height, utl::Progress& progress ); + + protected: + + //! Set nodes horizontal position, and return the resulting layout width. + float layoutNodesX( NodeSet& nodes ); + + //! . + Group* buildGroup( NodeSet& clusterNodes ); + //@} + //--------------------------------------------------------------------- + }; + } // ::qan::la +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // laTimeTree_h + ============================================================ --- libs/qanava/src/la/laVectorF.h b3718c42e0657dc330ffc9dab4fbbee849bff0be +++ libs/qanava/src/la/laVectorF.h b3718c42e0657dc330ffc9dab4fbbee849bff0be @@ -0,0 +1,176 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file laVectorF.h +// \author Benoit Autheman (address@hidden) +// \date 2004 February 15 +//----------------------------------------------------------------------------- + + +#ifndef laVectorF_h +#define laVectorF_h + + +// Qanava headers +#include "../utl/utlConfig.h" + + +// Standard headers +#include +#include + + +//----------------------------------------------------------------------------- +//! Root qanava namespace +namespace qan { // ::qan + //! Namespace for all graph related classes. + /*! 'la' originally stands for link analysis, even if the link analysis part has never been shipped with Qanava. */ + namespace la { // ::qan::la + + class VectorF + { + public: + + VectorF( ) : _length( 0 ), _data( 0 ) { } + + VectorF( unsigned int length ) : _length( length ), _data( 0 ) { _data = new double[ length ]; } + + VectorF( const VectorF& v ) + { + _length = v._length; + _data = new double[ v._length ]; + for ( unsigned int i = 0; i < v._length; i++ ) + _data[ i ] = v._data[ i ]; + } + + ~VectorF( ) { if ( _data != 0 ) delete _data; } + + double& operator()( unsigned int i ) { return _data[ i ]; } + + const double& operator()( unsigned int i ) const { return _data[ i ]; } + + double operator[]( unsigned int i ) const { return _data[ i ]; } + + void operator=( const VectorF& v ) + { + if ( _length == v._length && _data != 0 ) + { + for ( unsigned int i = 0; i < v._length; i++ ) + _data[ i ] = v._data[ i ]; + } + else + { + //if ( _data != 0 ) + // delete _data; + _length = v._length; + _data = new double[ v._length ]; + for ( unsigned int i = 0; i < v._length; i++ ) + _data[ i ] = v._data[ i ]; + } + } + + void operator/=( double f ) + { + for ( unsigned int i = 0; i < _length; i++ ) + _data[ i ] /= f; + } + + void operator*=( double f ) + { + for ( unsigned int i = 0; i < _length; i++ ) + _data[ i ] *= f; + } + + void operator+=( const VectorF& b ) + { + for ( unsigned int i = 0; i < _length; i++ ) + _data[ i ] += b._data[ i ]; + } + + void operator+=( double v ) + { + for ( unsigned int i = 0; i < _length; i++ ) + _data[ i ] += v; + } + + void operator-=( const VectorF& b ) + { + for ( unsigned int i = 0; i < _length; i++ ) + _data[ i ] -= b._data[ i ]; + } + + void operator/=( const VectorF& b ) + { + for ( unsigned int i = 0; i < _length; i++ ) + _data[ i ] /= b._data[ i ]; + } + + void operator*=( const VectorF& b ) + { + for ( unsigned int i = 0; i < _length; i++ ) + _data[ i ] *= b._data[ i ]; + } + + VectorF operator-( const VectorF& b ) const + { + VectorF result( _length ); + for ( unsigned int i = 0; i < _length; i++ ) + result._data[ i ] = _data[ i ] - b._data[ i ]; + return result; + } + + VectorF operator+( const VectorF& b ) const + { + VectorF result( _length ); + for ( unsigned int i = 0; i < _length; i++ ) + result._data[ i ] = _data[ i ] + b._data[ i ]; + return result; + } + + VectorF operator/( const VectorF& b ) const + { + VectorF result( _length ); + for ( unsigned int i = 0; i < _length; i++ ) + result._data[ i ] = _data[ i ] / b._data[ i ]; + return result; + } + + VectorF operator/( double f ) const + { + VectorF result( _length ); + for ( unsigned int i = 0; i < _length; i++ ) + result._data[ i ] = _data[ i ] / f; + return result; + } + + private: + + unsigned int _length; + + double* _data; + }; + } // ::qan::la +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // laVectorF_h ============================================================ --- libs/qanava/src/ui/uiItemListView.ui ad5879ef3b618c0553e56caeb7da103be279c7aa +++ libs/qanava/src/ui/uiItemListView.ui ad5879ef3b618c0553e56caeb7da103be279c7aa @@ -0,0 +1,37 @@ + + + + + ItemListView + + + + 0 + 0 + 152 + 351 + + + + Form + + + + 0 + + + 1 + + + + + true + + + + + + + + + ============================================================ --- libs/qanava/src/ui/uiNodesItemModel.cpp 8a2726a355ef1618de42a2e25c35660cf4eb2fc2 +++ libs/qanava/src/ui/uiNodesItemModel.cpp 8a2726a355ef1618de42a2e25c35660cf4eb2fc2 @@ -0,0 +1,173 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file uiNodesItemModel.cpp +// \author Benoit Autheman (address@hidden) +// \date 2006 August 30 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "./uiNodesItemModel.h" + + +// QT headers +#include + + +namespace qan { // ::qan +namespace ui { // ::qan::ui + + +//----------------------------------------------------------------------------- +NodesItemModel::NodesItemModel( la::Graph& graph, QObject *parent ) : + _graph( graph ) +{ + // Add a graph listenner + can::GraphItemListener* listener = new can::GraphItemListener( graph ); + _graph.addListener( listener ); + + connect( listener, SIGNAL( nodeInsertedBeginSig(qan::la::Node&) ), this, SLOT( nodeInsertedBegin(qan::la::Node&) ) ); + connect( listener, SIGNAL( nodeInsertedSig(qan::la::Node&) ), this, SLOT( nodeInserted(qan::la::Node&) ) ); + connect( listener, SIGNAL( nodeRemovedBeginSig(qan::la::Node&) ), this, SLOT( nodeRemovedBegin(qan::la::Node&) ) ); + connect( listener, SIGNAL( nodeRemovedSig(qan::la::Node&) ), this, SLOT( nodeRemoved(qan::la::Node&) ) ); +} + + +QVariant NodesItemModel::data( const QModelIndex &index, int role ) const +{ + if ( !index.isValid( ) ) + return QVariant( "index invalid" ); + + QVariant d; + + if ( ( role == Qt::FontRole ) && ( index.column( ) == 0 ) ) + { + QFont font; + font.setWeight( QFont::Bold ); + d = font; + } + + if ( role == Qt::DisplayRole ) + { + la::Node* node = _graph.findNode( index.row( ) ); + if ( node != 0 ) + { + if ( index.column( ) == 0 ) + d = QString( node->getLabel( ).c_str( ) ); + if ( index.column( ) > 0 ) + { + int attributeRole = index.column( ) - 1 + la::Node::StdAttributeCount; + if ( attributeRole < ( int )_graph.getAttributesCount( ) ) + { + std::string* attribute = node->getAttribute< std::string >( attributeRole ); + d = ( attribute != 0 ? QVariant( attribute->c_str( ) ) : QVariant( "" ) ); + } + } + } + } + + return d; +} + +bool NodesItemModel::hasChildren( const QModelIndex& parent ) const +{ + return false; +} + +Qt::ItemFlags NodesItemModel::flags( const QModelIndex& index ) const +{ + return ( index.isValid( ) ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::ItemIsEnabled ); +} + +QVariant NodesItemModel::headerData( int section, Qt::Orientation orientation, int role ) const +{ + QVariant d; + if ( role == Qt::DisplayRole ) + { + int attributeRole = section - 1 + la::Node::StdAttributeCount; + if ( section == 0 ) + return QString( "Label" ); + else if ( attributeRole >= 0 && attributeRole < ( int )_graph.getAttributesCount( ) ) + { + std::string attributeName = _graph.getAttributeName( attributeRole ); + d = QVariant( attributeName.c_str( ) ); + } + } + return d; +} + +QModelIndex NodesItemModel::index(int row, int column, const QModelIndex& parent ) const +{ + return createIndex( row, column, ( row * 10000 ) + column ); +} + +QModelIndex NodesItemModel::parent( const QModelIndex &index ) const +{ + return QModelIndex( ); +} + +int NodesItemModel::rowCount( const QModelIndex& parent ) const +{ + return _graph.getNodeCount( ); +} + +int NodesItemModel::columnCount( const QModelIndex& parent ) const +{ + return ( 1 + _graph.getAttributesCount( ) - la::Node::StdAttributeCount ); +} + +void NodesItemModel::nodeInsertedBegin( la::Node& node ) +{ + int id = _graph.findNode( node ); + if ( id != -1 ) + beginInsertRows( QModelIndex( ), id, id + 1 ); +} + +void NodesItemModel::nodeInserted( la::Node& node ) +{ + int id = _graph.findNode( node ); + if ( id != -1 ) + emit rowsInserted( QModelIndex( ), id, id + 1 ); + emit layoutChanged( ); +} + +void NodesItemModel::nodeRemovedBegin( la::Node& node ) +{ + int id = _graph.findNode( node ); + if ( id != -1 ) + beginRemoveRows( QModelIndex( ), id, id + 1 ); +} + +void NodesItemModel::nodeRemoved( la::Node& node ) +{ + int id = _graph.findNode( node ); + if ( id != -1 ) + endRemoveRows( ); + emit layoutChanged( ); +} +//----------------------------------------------------------------------------- + + +} // ::qan::ui +} // ::qan + ============================================================ --- libs/qanava/src/ui/uiNodesItemModel.h 9602a8cb289244281dba46cbae59153ba5720234 +++ libs/qanava/src/ui/uiNodesItemModel.h 9602a8cb289244281dba46cbae59153ba5720234 @@ -0,0 +1,105 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file uiNodesItemModel.h +// \author Benoit Autheman (address@hidden) +// \date 2006 August 30 +//----------------------------------------------------------------------------- + + +#ifndef uiNodesItemModel_h +#define uiNodeSItemModel_h + + +// Qanava headers +#include "../la/laGraph.h" +#include "../can/canGraphItemModel.h" + + +// QT headers +#include + + +//----------------------------------------------------------------------------- +namespace qan // ::qan +{ + namespace ui // ::qan::ui + { + //! . + /*! + \nosubgrouping + */ + class NodesItemModel : public QAbstractItemModel + { + Q_OBJECT + + public: + + NodesItemModel( la::Graph& graph, QObject *parent = 0 ); + + virtual QVariant data( const QModelIndex &index, int role ) const; + + virtual bool hasChildren( const QModelIndex & parent = QModelIndex( ) ) const; + + virtual Qt::ItemFlags flags( const QModelIndex &index ) const; + + virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; + + virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + + virtual QModelIndex parent( const QModelIndex &index ) const; + + virtual int rowCount( const QModelIndex& parent = QModelIndex( ) ) const; + + virtual int columnCount( const QModelIndex& parent = QModelIndex( ) ) const; + + signals: + + void rowsInserted( const QModelIndex& parent, int start, int end ); + + void rowsRemoved( const QModelIndex& parent, int start, int end ); + + protected slots: + + virtual void nodeInsertedBegin( qan::la::Node& node ); + + virtual void nodeInserted( qan::la::Node& node ); + + virtual void nodeRemovedBegin( qan::la::Node& node ); + + virtual void nodeRemoved( qan::la::Node& node ); + + private: + + la::Graph& _graph; + + bool getShowStdAttributes( ) const { return _showStdAttributes; } + + bool _showStdAttributes; + }; + } // ::qan::ui +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // uiStyleEditor_h + ============================================================ --- libs/qanava/src/ui/uiStyleModel.cpp 9027a6909c05fbe08532f4430bad71468e6b515e +++ libs/qanava/src/ui/uiStyleModel.cpp 9027a6909c05fbe08532f4430bad71468e6b515e @@ -0,0 +1,151 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Mysire software. +// +// \file uiStyleItemModel.cpp +// \author Benoit Autheman (address@hidden) +// \date 2006 January 04 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "./uiStyleModel.h" + + +namespace qan { // ::qan +namespace ui { // ::qan::ui + + +//----------------------------------------------------------------------------- + StyleItemModel::StyleItemModel( can::Style& style, QObject *parent ) : + QAbstractItemModel( parent ), + _style( style ) +{ + +} +//----------------------------------------------------------------------------- + + + +/* Qt Model Interface *///----------------------------------------------------- +QVariant StyleItemModel::data( const QModelIndex &index, int role ) const +{ + if ( !index.isValid( ) ) + return QVariant( "index invalid" ); + + QVariant d; + + if ( ( role == Qt::FontRole ) && ( index.column( ) == 0 ) ) + { + QFont font; + font.setWeight( QFont::Bold ); + d = font; + } + + if ( role == Qt::DisplayRole ) + { + if ( index.column( ) == 0 ) + { + d = QString( "ATTR NAME" ); + } + else if ( index.column( ) == 1 ) + { + d = QString( "FIXME: StyleItemModel::data()!" ); + } + } + + return d; +} + +bool StyleItemModel::hasChildren( const QModelIndex & parent ) const +{ + return false; // No hierarchy for articles +} + +Qt::ItemFlags StyleItemModel::flags( const QModelIndex &index ) const +{ + if ( !index.isValid( ) ) + return Qt::ItemIsEnabled; + + if ( index.column( ) == 0 ) + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + else if ( index.column( ) == 1 ) + return Qt::ItemIsEnabled | Qt::ItemIsEditable; + + return Qt::ItemIsEnabled; +} + +QVariant StyleItemModel::headerData( int section, Qt::Orientation orientation, int role ) const +{ + if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) + { + if ( section == 0 ) + return QString( "Property" ); + else if ( section == 1 ) + return QString( "Value" ); + } + return QVariant( ); +} + +QModelIndex StyleItemModel::index( int row, int column, const QModelIndex &parent ) const +{ + if ( !parent.isValid( ) ) + { + const void* internalPointer = 0; + int internalId = 0; + + //can::Style::Attribute* attribute = _style.getAttributeManager( ).get( row ); + //if ( attribute != 0 ) + //{ + if ( column == 0 ) + internalId = 100 + row; + else if ( column == 1 ) + internalId = 200 + row; + // FIXME internalPointer = 200 + row; // FIXME attribute; + //} + + if ( internalPointer != 0 ) + return createIndex( row, column, const_cast< void* >( internalPointer ) ); + else if ( internalId != 0 ) + return createIndex( row, column, internalId ); + } + return QModelIndex( ); +} + +QModelIndex StyleItemModel::parent( const QModelIndex &index ) const +{ + return QModelIndex( ); // No hierarchy for articles +} + +int StyleItemModel::rowCount( const QModelIndex& parent ) const +{ + return _style.size( ); +} + +int StyleItemModel::columnCount( const QModelIndex& parent ) const +{ + return 2; +} +//----------------------------------------------------------------------------- + + +} // ::qan::ui +} // ::qan ============================================================ --- libs/qanava/src/ui/uiStyleModel.h 8646ef850e3bd7efb64c147018f6f65aa0e6c76d +++ libs/qanava/src/ui/uiStyleModel.h 8646ef850e3bd7efb64c147018f6f65aa0e6c76d @@ -0,0 +1,103 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Mysire software. +// +// \file uiStyleItemModel.h +// \author Benoit Autheman (address@hidden) +// \date 2006 January 04 +//----------------------------------------------------------------------------- + + +#ifndef uiStyleItemModel_h +#define uiStyleItemModel_h + + +// Qanava headers +#include "../la/laGraph.h" +#include "../can/canStyle.h" + + +// QT headers +#include +#include +#include + + +//----------------------------------------------------------------------------- +namespace qan // ::qan +{ + namespace ui // ::qan::ui + { + //! . + /*! + \nosubgrouping + */ + class StyleItemModel : public QAbstractItemModel + { + Q_OBJECT + + public: + + StyleItemModel( can::Style& style, QObject *parent = 0 ); + + private: + + can::Style& _style; + + /*! \name Qt Model Interface *///---------------------------------- + //@{ + public: + + //! Define the article attribute offset (row) in table. + enum AttributeOffset + { + TITLE = 0, + AUTHOR = 1, + SOURCE = 2, + SUB = 3, + SUP = 4 + }; + + virtual QVariant data( const QModelIndex &index, int role ) const; + + virtual bool hasChildren( const QModelIndex & parent = QModelIndex( ) ) const; + + virtual Qt::ItemFlags flags( const QModelIndex &index ) const; + + virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + + virtual QModelIndex parent( const QModelIndex &index ) const; + + virtual int rowCount( const QModelIndex& parent = QModelIndex( ) ) const; + + virtual int columnCount( const QModelIndex& parent = QModelIndex( ) ) const; + //@} + //----------------------------------------------------------------- + }; + } // ::qan::ui +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // uiStyleItemModel_h + ============================================================ --- libs/qanava/src/ui/uiStyleView.cpp e357ecea2bab03cbc6e958a8168219615c6dc536 +++ libs/qanava/src/ui/uiStyleView.cpp e357ecea2bab03cbc6e958a8168219615c6dc536 @@ -0,0 +1,385 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file uiStyleView.cpp +// \author Benoit Autheman (address@hidden) +// \date 2005 December 23 +//----------------------------------------------------------------------------- + + +// Qanava headers +#include "./uiStyleView.h" +#include "../can/canStyle.h" + + +// QT headers +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace qan { // ::qan +namespace ui { // ::qan::ui + + +ColorEditWidget::ColorEditWidget( QWidget* parent, QColor color ) : + QWidget( parent ), + _label( 0 ), + _color( color ) +{ + setAutoFillBackground( true ); // Delegate widget are transparent by default + + QHBoxLayout* hbox = new QHBoxLayout( this ); + hbox->setMargin( 0 ); + hbox->setSpacing( 1 ); + + _label = new QLabel( this ); + _label->setText( _color.name( ) ); + + QPushButton* b = new QPushButton( "...", parent ); + b->setText( "..." ); + b->setMaximumWidth( 40 ); + connect( b, SIGNAL( clicked() ), this, SLOT( selectColor() ) ); + + hbox->addSpacing( 2 ); + hbox->addWidget( _label ); + hbox->addWidget( b ); + + setColor( color ); +} + +void ColorEditWidget::setColor( QColor color ) +{ + _color = color; + + QPalette palette; + palette.setColor( backgroundRole( ), _color ); + setPalette( palette ); + + QColor colorHsv = color.toHsv( ); + QColor textColor( colorHsv.saturation( ) < 127 ? Qt::black : Qt::white ); + palette = _label->palette( ); + palette.setColor( QPalette::Text, textColor ); + _label->setPalette( palette ); + _label->setText( _color.name( ) ); +} + +void ColorEditWidget::selectColor( ) +{ + QColor color = QColorDialog::getColor( _color, this ); + setColor( color ); + close( ); + /*if ( _delegate != 0 ) + emit _delegate->commitData( this );*/ +} + + +StringEditWidget::StringEditWidget( QWidget* parent, QString s ) : + QWidget( parent ), + _edit( 0 ), + _string( s ) +{ + setAutoFillBackground( true ); // Delegate widget are transparent by default + + QHBoxLayout* hbox = new QHBoxLayout( this ); + hbox->setMargin( 0 ); + hbox->setSpacing( 1 ); + + _edit = new QLineEdit( this ); + _edit->setFrame( false ); + + QPushButton* b = new QPushButton( "...", parent ); + b->setText( "..." ); + b->setMaximumWidth( 40 ); + connect( b, SIGNAL( clicked() ), this, SLOT( selectString() ) ); + + hbox->addSpacing( 2 ); + hbox->addWidget( _edit ); + hbox->addWidget( b ); + connect( _edit, SIGNAL( editingFinished() ), this, SLOT( editingFinished() ) ); + setString( s ); +} + +void StringEditWidget::setString( QString s ) +{ + _edit->setText( s ); + _edit->selectAll( ); + _string = s; +} + +void StringEditWidget::selectString( ) +{ + QString s = QFileDialog::getOpenFileName( this, "Choose an image file", "./", "Images (*.png *.jpg)" ); + if ( !s.isEmpty( ) ) + setString( s ); +} + +void StringEditWidget::editingFinished( ) +{ + setString( _edit->text( ) ); +} + + +StyleDelegate::StyleDelegate( QAbstractItemModel& model ) : + _model( model ) +{ + setItemEditorFactory( new QItemEditorFactory( ) ); +} + +QWidget* StyleDelegate::createEditor ( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + QWidget* editor = 0; + + QPalette palette( parent->palette( ) ); + + QVariant attribute = _model.data( index ); + switch ( attribute.type( ) ) + { + case QVariant::String: + { + QString s = attribute.toString( ); + editor = new StringEditWidget( parent, s ); + editor->setPalette( palette ); + } + break; + case QVariant::Color: + { + QColor color = attribute.value< QColor >( ); + editor = new ColorEditWidget( parent, color ); + } + break; + default: + editor = itemEditorFactory( )->createEditor( attribute.type( ), parent ); + break; + }; + + if ( editor != 0 ) + editor->installEventFilter( const_cast< StyleDelegate* >( this ) ); + else + return QItemDelegate::createEditor( parent, option, index ); + + return editor; +} + +void StyleDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const +{ + if ( !index.isValid( ) || index.row( ) == 0 || index.column( ) != 1 ) + { + QItemDelegate::paint( painter, option, index ); + return; + } + + QVariant attribute = _model.data( index ); + switch ( attribute.type( ) ) + { + case QVariant::Color: + { + QColor color = attribute.value< QColor >( ); + + painter->save( ); // StyleOption option does not work for back color + painter->setPen( Qt::NoPen ); + painter->setBrush( color ); + painter->drawRect( option.rect ); + painter->restore( ); + + // Invert text color to avoid text beeing unreadable + QColor colorHsv = color.toHsv( ); + QColor textColor( colorHsv.saturation( ) < 127 ? Qt::black : Qt::white ); + QStyleOptionViewItem customOption( option ); + customOption.palette.setColor( QPalette::Text, textColor ); + drawDisplay( painter, customOption, option.rect, color.name( ) ); + break; + } + default: + QItemDelegate::paint( painter, option, index ); + break; + }; +} + +void StyleDelegate::setEditorData( QWidget* editor, const QModelIndex& index ) const +{ + QVariant attribute = _model.data( index ); + + switch ( attribute.type( ) ) + { + case QVariant::String: + { + StringEditWidget* w = static_cast< StringEditWidget* >( editor ); + QVariant attribute = _model.data( index ); + w->setString( attribute.toString( ) ); + } + break; + case QVariant::Color: + { + ColorEditWidget* w = static_cast< ColorEditWidget* >( editor ); + QVariant attribute = _model.data( index ); + w->setColor( attribute.value< QColor >( ) ); + } + break; + default: + QItemDelegate::setEditorData( editor, index ); + break; + }; +} + +void StyleDelegate::setModelData( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index ) const +{ + QVariant attribute = model->data( index ); + + switch ( attribute.type( ) ) + { + case QVariant::String: + { + StringEditWidget* w = static_cast< StringEditWidget* >( editor ); + model->setData( index, w->getString( ) ); + } + break; + case QVariant::Color: + { + ColorEditWidget* w = static_cast< ColorEditWidget* >( editor ); + model->setData( index, w->getColor( ) ); + } + break; + default: + QItemDelegate::setModelData( editor, model, index ); + break; + }; +} + +QSize StyleDelegate::sizeHint ( const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + return QSize( 50, 15 ); +} + + + +//----------------------------------------------------------------------------- +StyleEditor::StyleEditor( QWidget* parent, can::Style* style ) : + QMainWindow( parent ), + _style( style ), + _tableView( 0 ), + _cbType( 0 ) +{ + if ( layout( ) != 0 ) + { + layout( )->setMargin( 0 ); + layout( )->setSpacing( 1 ); + } + QToolBar* toolBar = addToolBar( "Tools" ); + if ( toolBar->layout( ) != 0 ) + toolBar->layout( )->setMargin( 2 ); + toolBar->setIconSize( QSize( 16, 16 ) ); + + _cbType = new QComboBox( toolBar ); + _cbType->addItem( QIcon(), "<< Type >>" ); + _cbType->addItem( QIcon(), "Color" ); + _cbType->addItem( QIcon(), "String" ); + _cbType->addItem( QIcon(), "Image" ); + _cbType->addItem( QIcon(), "Int" ); + _cbType->addItem( QIcon(), "Double" ); + + QToolButton* addAttribute = new QToolButton( toolBar ); + addAttribute->setIcon( QIcon( "images/qanava_plus.png" ) ); + addAttribute->setAutoRaise( true ); + connect( addAttribute, SIGNAL( clicked() ), this, SLOT( addAttribute() ) ); + + QToolButton* removeAttribute = new QToolButton( parent ); + removeAttribute->setIcon( QIcon( "images/qanava_minus.png" ) ); + removeAttribute->setAutoRaise( true ); + connect( removeAttribute, SIGNAL( clicked() ), this, SLOT( removeAttribute() ) ); + + toolBar->addWidget( _cbType ); + //toolBar->addSeparator( ); + toolBar->addWidget( addAttribute ); + toolBar->addWidget( removeAttribute ); + + _tableView = new QTableView( this ); + _tableView->setAlternatingRowColors( true ); + _tableView->setMaximumWidth( 200 ); + _tableView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + _tableView->horizontalHeader( )->resizeSections( QHeaderView::Fixed ); // Fixed + _tableView->horizontalHeader( )->setStretchLastSection( true ); + _tableView->verticalHeader( )->resizeSections( QHeaderView::Fixed ); + _tableView->verticalHeader( )->setDefaultSectionSize( 20 ); + _tableView->verticalHeader( )->hide( ); + + setCentralWidget( _tableView ); + setStyle( style ); +} + +void StyleEditor::setStyle( can::Style* style ) +{ + if ( style != 0 ) + { + _style = style; + _tableView->setDisabled( false ); + _tableView->setItemDelegate( new ui::StyleDelegate( *style ) ); + _tableView->setModel( style ); + } + else + { + _style = 0; + _tableView->reset( ); + _tableView->setDisabled( true ); + } +} + +void StyleEditor::addAttribute( ) +{ + QString attrName( "New attribute " ); + attrName += QString::number( _style->size( ) ); + switch ( _cbType->currentIndex( ) ) + { + case 1: // Color + _style->add( attrName, Qt::black ); + break; + case 2: // String + _style->add( attrName, QString( "" ) ); + break; + case 3: // Image + break; + case 4: // Int + break; + case 5: // Double + break; + default: + break; + } +} + +void StyleEditor::removeAttribute( ) +{ + +} +//----------------------------------------------------------------------------- + + +} // ::qan::ui +} // ::qan + ============================================================ --- libs/qanava/src/ui/uiStyleView.h 33c1b960b744e41f1b9fd1bbff5f046df28ab91e +++ libs/qanava/src/ui/uiStyleView.h 33c1b960b744e41f1b9fd1bbff5f046df28ab91e @@ -0,0 +1,171 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file uiStyleView.h +// \author Benoit Autheman (address@hidden) +// \date 2005 December 23 +//----------------------------------------------------------------------------- + + +#ifndef uiStyleEditor_h +#define uiStyleEditor_h + + +// Qanava headers +#include "../can/canStyle.h" + + +// QT headers +#include +#include +#include +#include +#include +#include +#include +#include + + +//----------------------------------------------------------------------------- +namespace qan // ::qan +{ + //! Namespace for all high level widgets used to edit and control objects from the can and la frameworks. + namespace ui // ::qan::ui + { + class ColorEditWidget : public QWidget + { + Q_OBJECT + + public: + + ColorEditWidget( QWidget* parent, QColor color ); + + QColor getColor( ) { return _color; } + + void setColor( QColor color ); + + protected: + + QLabel* _label; + + QColor _color; + + private slots: + + void selectColor( ); + }; + + class StringEditWidget : public QWidget + { + Q_OBJECT + + public: + + StringEditWidget( QWidget* parent, QString s ); + + QString getString( ) { return _string; } + + void setString( QString s ); + + protected: + + QLineEdit* _edit; + + QString _string; + + private slots: + + void selectString( ); + + void editingFinished( ); + }; + + class StyleDelegate : public QItemDelegate + { + public: + + StyleDelegate( QAbstractItemModel& model /*QAbstractItemView& tableView*/ ); + + virtual QWidget* createEditor ( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const; + + virtual void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; + + virtual void setEditorData( QWidget* editor, const QModelIndex& index ) const; + + virtual void setModelData( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index ) const; + + virtual QSize sizeHint ( const QStyleOptionViewItem& option, const QModelIndex& index ) const; + + protected: + + QAbstractItemModel& _model; + }; + + + + //! + /*! + \nosubgrouping + */ + class StyleEditor : public QMainWindow + { + Q_OBJECT + + public: + + StyleEditor( QWidget* parent = 0, can::Style* style = 0 ); + + virtual ~StyleEditor( ) { } + + private: + + StyleEditor( const StyleEditor& ); + + StyleEditor& operator=( const StyleEditor& ); + + public: + + void setStyle( can::Style* style ); + + virtual QSize sizeHint( ) const { return QSize( 150, 200 ); } + + protected slots: + + void addAttribute( ); + + void removeAttribute( ); + + protected: + + can::Style* _style; + + QTableView* _tableView; + + QComboBox* _cbType; + }; + } // ::qan::ui +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // uiStyleEditor_h + ============================================================ --- libs/qanava/src/ui/uiStyleView.ui 3415d8ca187cfc1de191578b704cdd0d20fda3ff +++ libs/qanava/src/ui/uiStyleView.ui 3415d8ca187cfc1de191578b704cdd0d20fda3ff @@ -0,0 +1,37 @@ + + + + + StyleView + + + + 0 + 0 + 152 + 351 + + + + Form + + + + 0 + + + 1 + + + + + true + + + + + + + + + ============================================================ --- libs/qanava/src/ui/uiUtil.h 358bed6be6af36e35187e4d18a2ac8e29f8d5fb4 +++ libs/qanava/src/ui/uiUtil.h 358bed6be6af36e35187e4d18a2ac8e29f8d5fb4 @@ -0,0 +1,58 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava software. +// +// \file uiUtil.h +// \author Benoit Autheman (address@hidden) +// \date 2006 January 07 +//----------------------------------------------------------------------------- + + +#ifndef uiUtil_h +#define uiUtil_h + + +// STD headers +#include + + +//----------------------------------------------------------------------------- +namespace qan // ::qan +{ + namespace ui // ::qan::ui + { + + //! Utility method for nodes and edges lists models. + template < typename Item > + static Item listGet( std::list< Item >& l, unsigned int id ) + { + unsigned int i = 0; + typename std::list< Item >::iterator itemIter = l.begin( ); + for ( ; ( i < id ) && ( itemIter != l.end( ) ); itemIter++, i++ ) { } + return ( itemIter != l.end( ) ? *itemIter : 0 ); + } + } // ::qan::ui +} // ::qan +//----------------------------------------------------------------------------- + + +#endif // uiUtil_h + ============================================================ --- libs/qanava/src/utl/utlConfig.h e45de8e04055ac0b668eccc0eb2281dd8f2d591b +++ libs/qanava/src/utl/utlConfig.h e45de8e04055ac0b668eccc0eb2281dd8f2d591b @@ -0,0 +1,57 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava and LTM software. +// +// \file utlConfig.h +// \author Benoit Autheman (address@hidden) +// \date 2004 September 21 +//----------------------------------------------------------------------------- + + +#ifndef qan_utlConfig_h +#define qan_utlConfig_h + + +// Configure this file either for LTM or Qanava +#undef QAN_UTL_ROOT_NAMESPACE +#define QAN_UTL_ROOT_NAMESPACE qan // Uncomment for Qanava +//#define QAN_UTL_ROOT_NAMESPACE ltm // Uncomment for LTM + +#include + +#ifndef QANAVA_LINUX + +#pragma warning( disable:4786 ) // VC6: Too long template name in debug informations + +#pragma warning( disable:4251 ) // VC7.1: BOOST dll interface warning + +#pragma warning( disable:4275 ) // VC7.1: BOOST dll interface warning + +#pragma warning( disable:4290 ) // VC7.1: Explicit C++ exception specification + +#pragma warning( disable:4100 ) // VC7.1: Unreferenced formal parameter + +#pragma warning( disable:4244 ) // VC7.1: BOOST date and time warning + +#endif + +#endif // utlConfig_h + ============================================================ --- libs/qanava/src/utl/utlManager.h b17e0d2c98e6b0181518b29c47a000c162a62ce3 +++ libs/qanava/src/utl/utlManager.h b17e0d2c98e6b0181518b29c47a000c162a62ce3 @@ -0,0 +1,193 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava and LTM software. +// +// \file utlManager.h +// \author Benoit Autheman (address@hidden) +// \date 2003 June 02 +//----------------------------------------------------------------------------- + + +#ifndef qan_utlManager_h +#define qan_utlManager_h + + +// LTM headers +#include "./utlConfig.h" + + +// Standard includes +#include +#include +#include + + +//----------------------------------------------------------------------------- +namespace QAN_UTL_ROOT_NAMESPACE // ::QAN_UTL_ROOT_NAMESPACE +{ + namespace utl // ::QAN_UTL_ROOT_NAMESPACE::utl + { + //! Empty glue class for all generic managers. + /*! + \nosubgrouping + */ + class ManagerBase + { + public: + + //! Mode of maangement. + enum Mode + { + //! Mode undefined. + UNDEFINED = 1, + + //! Elements are just shared by the manager and left unmodified after manager destruction. + SHARED = 2, + + //! Elements are owned by the manager and freed during the manager destruction. + OWNED = 4 + }; + }; + + + //! Manage a group of generic object instances. + /*! + Support the virtual model behaviour trought the apropriate signals. + + \nosubgrouping + */ + template < class Item > + class Manager : public ManagerBase + { + /*! \name Manager Constructor/Destructor *///---------------------- + //@{ + public: + + //! Manager constructor. + Manager( Mode mode = OWNED ); + + //! Manager destructor. + virtual ~Manager( ); + + private: + + //! Manager empty private copy constructor. + Manager( const Manager< Item >& manager ) : _mode( manager.mode ) { } + //@} + //----------------------------------------------------------------- + + + + /*! \name Items management *///------------------------------------ + //@{ + public: + + //! STL vector of pointer to item type definition. + typedef std::list< Item* > Items; + + //! Shortcut to the equivalent stl container member. + typedef typename Items::iterator iterator; + + //! Shortcut to the equivalent stl container member. + typedef typename Items::const_iterator const_iterator; + + //! Shortcut to the equivalent stl container member. + unsigned int size( ) const { return ( unsigned int )_items.size( ); } + + //! Shortcut to the equivalent stl container member. + iterator begin( ) { return _items.begin( ); } + + //! Shortcut to the equivalent stl container member. + const_iterator begin( ) const { return _items.begin( ); } + + //! Shortcut to the equivalent stl container member. + iterator end( ) { return _items.end( ); } + + //! Shortcut to the equivalent stl container member. + const_iterator end( ) const { return _items.end( ); } + + //! Get a const reference on the manager items list. + /*! \return Manager items list const reference. */ + const Items& getItems( ) const { return _items; } + + //! Get a reference on the manager items list. + /*! \return Manager items list reference. */ + Items& getItems( ) { return _items; } + + //! Register an item by adding its reference to manager item list. + virtual void add( Item& item ); + + //! Register a list of items by adding their references to this manager. + virtual void add( Items& items ); + + //! Remove an item from this manager. + virtual void remove( Item& item ); + + //! Test if an item is registered in the manager. + bool has( Item& item ) const; + + //! Clear the database of all managed items. + void clear( bool destroy = false ); + + //! Return the manager first item pointer (0 if manager is empty). + Item* first( ); + + //! Return a pointer on th ith managed object. + Item* get( unsigned int index ); + + //! Return a const pointer on th ith managed object. + const Item* get( unsigned int index ) const; + + //! Return the manager mode. + Mode getMode( ) const { return _mode; } + + private: + + //! Management mode. + Mode _mode; + + //! Internal list of item registered in the manager. + Items _items; + //@} + //----------------------------------------------------------------- + + + + /*! \name Model Signals Management *///---------------------------- + //@{ + public: + + void modified( ) { } + + void destroyed( ) { } + //@} + //----------------------------------------------------------------- + }; + } // ::ROOT_NAMESPACE::utl +} // ::ROOT_NAMESPACE +//----------------------------------------------------------------------------- + + +#include "./utlManager.hpp" + + +#endif // qan/ltm_utlManager_h + ============================================================ --- libs/qanava/src/utl/utlManager.hpp 7cb1fd07f16f0e6bda399805c7b79779aff739fd +++ libs/qanava/src/utl/utlManager.hpp 7cb1fd07f16f0e6bda399805c7b79779aff739fd @@ -0,0 +1,155 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava and LTM software. +// +// \file utlManager.cpp +// \author Benoit Autheman (address@hidden) +// \date 2003 June 02 +//----------------------------------------------------------------------------- + + +namespace QAN_UTL_ROOT_NAMESPACE { // ::QAN_UTL_ROOT_NAMESPACE +namespace utl { // ::QAN_UTL_ROOT_NAMESPACE::utl + + +/* Manager Constructor/Destructor *///--------------------------------------- +template < class Item > +Manager< Item >::Manager( Mode mode ) : + _mode( mode ) +{ + +} + +template < class Item > +Manager< Item >::~Manager( ) +{ + // If the element are owned by the manager, delete them at the manager destruction + if ( _mode == OWNED ) + clear( true ); + + destroyed( ); +} +//----------------------------------------------------------------------------- + + +/* management *///------------------------------------------------------------- +template < class Item > +bool Manager< Item >::has( Item& item ) const +{ + const_iterator iter = std::find( begin( ), end( ), &item ); + return ( iter != end( ) ); +} + +/*! + \param destroy Delete the items if true, delete the manager reference otherwise. +*/ +template < class Item > +void Manager< Item >::clear( bool destroy ) +{ + if ( destroy == true ) + { + for ( iterator itemIter = begin( ); itemIter != end( ); itemIter++ ) + delete *itemIter; + } + + // Destroy the item reference anyways + _items.clear( ); + + // Refresh the view dependant of this manager + modified( ); +} + +/*! + \return Pointer on the manager first item. 'null' if manager is empty. +*/ +template < class Item > +Item* Manager< Item >::first( ) +{ + if ( begin( ) != end( ) ) + return *begin( ); + return 0; +} + +/*! + A 'modified' notification is emitted after the adjunction (If you are planning to add + multiple items, consider using the 'addItems()' method to have a single notification + for all adjunction). + \param item Item to register in manager. +*/ +template < class Item > +void Manager< Item >::add( Item& item ) +{ + _items.push_back( &item ); + modified( ); +} + +/*! + \param item Item to register in manager. +*/ +template < class Item > +void Manager< Item >::add( Items& items ) +{ + for ( iterator itemIter = items.begin( ); itemIter != items.end( ); itemIter++ ) + _items.push_back( *itemIter ); + modified( ); +} + +/*! + \param item Item to remove from this manager. +*/ +template < class Item > +void Manager< Item >::remove( Item& item ) +{ + _items.remove( &item ); + modified( ); +} + +/*! + \param index Index of the object to access. + \return Pointer on the manager ith object. null if there is no such object. +*/ +template < class Item > +Item* Manager< Item >::get( unsigned int index ) +{ + if ( index >= _items.size( ) ) + return 0; + typename Items::iterator itemIter = _items.begin( ); + for ( unsigned int n = 0; n < index; n++ ) + itemIter++; + return *itemIter; +} + +template < class Item > +const Item* Manager< Item >::get( unsigned int index ) const +{ + if ( index >= _items.size( ) ) + return 0; + typename Items::const_iterator itemIter = _items.begin( ); + for ( unsigned int n = 0; n < index; n++ ) + itemIter++; + return *itemIter; +} +//----------------------------------------------------------------------------- + + +} // ::QAN_UTL_ROOT_NAMESPACE::utl +} // ::QAN_UTL_ROOT_NAMESPACE + ============================================================ --- libs/qanava/src/utl/utlProgress.cpp 03f6517f44e4b70b18e365216395b5367ae27e30 +++ libs/qanava/src/utl/utlProgress.cpp 03f6517f44e4b70b18e365216395b5367ae27e30 @@ -0,0 +1,55 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava and LTM software. +// +// \file utlProgress.cpp +// \author Benoit Autheman (address@hidden) +// \date 2004 July 08 +//----------------------------------------------------------------------------- + + +// UTL includes +#include "./utlProgress.h" + + +namespace QAN_UTL_ROOT_NAMESPACE { // ::QAN_UTL_ROOT_NAMESPACE +namespace utl { // ::QAN_UTL_ROOT_NAMESPACE::utl + + +/* Progress Management *///---------------------------------------------------- +void Progress::reset( int maxProgress ) +{ + setProgress( 0 ); + setMaxProgress( maxProgress ); +} + +/*void Progress::setProgress( int progress ) +{ + _progress = progress; + if ( _maxProgress != 0 ) + updateProgress( progress * 100 / _maxProgress ); +}*/ +//----------------------------------------------------------------------------- + + +} // ::QAN_UTL_ROOT_NAMESPACE::utl +} // ::QAN_UTL_ROOT_NAMESPACE + ============================================================ --- libs/qanava/src/utl/utlProgress.h 2c595ced20ea2b3c0e8d9358e89583d88fa9f3ab +++ libs/qanava/src/utl/utlProgress.h 2c595ced20ea2b3c0e8d9358e89583d88fa9f3ab @@ -0,0 +1,141 @@ +/* +Qanava - Graph drawing library for QT +Copyright (C) 2006 Benoit AUTHEMAN + +This 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 +*/ + +//----------------------------------------------------------------------------- +// This file is a part of the Qanava and LTM software. +// +// \file utlProgress.h +// \author Benoit Autheman (address@hidden) +// \date 2005 July 08 +//----------------------------------------------------------------------------- + + +#ifndef qan_utlProgress_h +#define qan_utlProgress_h + + +// UTL headers +#include "./utlConfig.h" + + +//----------------------------------------------------------------------------- +namespace QAN_UTL_ROOT_NAMESPACE // ::QAN_UTL_ROOT_NAMESPACE +{ + namespace utl // ::QAN_UTL_ROOT_NAMESPACE::utl + { + //! Abstract class used to provide feedback about a task progression. + /*! + \nosubgrouping + */ + class Progress + { + /*! \name Progress Constructor/Destructor *///------------------------ + //@{ + public: + + //! Progress constructor. + Progress( int maxProgress = 100 ) : + _progress( 0 ), + _maxProgress( maxProgress ) { } + + //! Progress destructor. + virtual ~Progress( ) { } + + protected: + + //! Progress empty private copy constructor. + Progress( const Progress& progress ) { } + //@} + //----------------------------------------------------------------- + + + + /*! \name Progress Management *///--------------------------------- + //@{ + public: + + //! . + void reset( int maxProgress ); + + //! . + void setProgress( int progress ) + { + _progress = progress; + if ( _maxProgress != 0 ) + updateProgress( progress * 100 / _maxProgress ); + } + + //! . + int getProgress( ) const { return _progress; } + + //! . + void incProgress( ) { setProgress( getProgress( ) + 1 ); } + + //! . + virtual void setMaxProgress( int maxProgress ) { _maxProgress = maxProgress; } + + //! . + virtual bool getCancel( ) = 0; + + //! . + void finish( ) { setProgress( _maxProgress ); } + + protected: + + //! + virtual void updateProgress( int percent ) = 0; + + //! . + int _progress; + + //! . + int _maxProgress; + //@} + //----------------------------------------------------------------- + }; + + + + //! Progress default concrete implementation. + /*! + \nosubgrouping + */ + class ProgressVoid : public Progress + { + /*! \name Progress Management *///--------------------------------- + //@{ + public: + + //! . + virtual bool getCancel( ) { return false; } + + protected: + + //! . + virtual void updateProgress( int /*percent*/ ) { } + //@} + //----------------------------------------------------------------- + }; + } // ::QAN_UTL_ROOT_NAMESPACE::utl +} // ::QAN_UTL_ROOT_NAMESPACE +//----------------------------------------------------------------------------- + + +#endif // qan_utlProgress_h + ============================================================ --- .mtn-ignore d12ed1ba7c0f020192430ea692ad88d953b74cb0 +++ .mtn-ignore 73f2fd80083fdbd3aa6c139bbefd78727f2cffb2 @@ -1,6 +1,7 @@ guitone\.xcodeproj Makefile guitone\.xcodeproj +guitone\/res\/i18n\/.+\.qm +guitone\/tmp.* +guitone\/bin/.* +\.moc +\.obj -Info.plist -res\/i18n\/.+\.qm -tmp.* -bin/.* ============================================================ --- README 3becea4a889f548a17cdfb9c9f504d181b5d9834 +++ README 42ca1d930985fcd7e53b87f05e1774ad41213e0f @@ -6,7 +6,7 @@ to browse through the workspace contents just like a normal file browser, but by displaying additional file status information. -You need Qt >= 4.1 and monotone >= 0.30 (0.29 works as well but has a bug +You need Qt >= 4.2 and monotone >= 0.30 (0.29 works as well but has a bug in the attributes display) to build and later run monotone. Under Linux / MacOS X just do @@ -24,7 +24,7 @@ and open this with XCode. If you need to tweak settings (i.e. architecture) in the Qt project file (guitone.pro), remember to redo this step. -The created binary is monolithic can be found in bin/. +The created binary is monolithic can be found in guitone/bin. The most recent version can always be obtained from the monotone ============================================================ --- build.sh 34a577b8e06c930c6508418e3036426b7210d6f1 +++ build.sh f2e5495f9013a8b24e8dfecffea3015ea68f86d1 @@ -1,6 +1,10 @@ #!/bin/sh -qmake guitone.pro && \ + +qmake guitone.pro + +cd guitone && \ lupdate guitone.pro && \ lrelease guitone.pro && \ + cd .. make $@ ============================================================ --- guitone/res/i18n/guitone_de.ts 3b0993a128ae9a40dbf4ace8009c6c82adc0c349 +++ guitone/res/i18n/guitone_de.ts 9857927823e1d6a0339b531c120dcaadd22d25e9 @@ -1,31 +1,39 @@ - + + Attributes + added hinzugefügt + dropped entfernt + changed verändert + unchanged unverändert + Key Schlüssel + Value Wert + State Status @@ -33,6 +41,7 @@ Branches + Branch Name Zweig-Name @@ -40,42 +49,52 @@ Certs + ok OK + bad schlecht + unknown unbekannt + trusted vertrauenswürdig + untrusted nicht vertrauenswürdig + Key Schlüssel + Name Name + Value Wert + Signature Signatur + Trust Vertrauen @@ -83,129 +102,160 @@ Guitone + guitone - a frontend for monotone guitone - ein Frontend für monotone + &File &Datei + &Import Sandbox... Arbeitsbereich &importieren + &Quit &Beenden + Ready Bereit + Select your workspace... Wählen Sie Ihren Arbeitsbereich aus... + Loading aborted Laden abgebrochen + Invalid workspace Ungültiger Arbeitsbereich + The chosen directory is no monotone sandbox! Das gewählte Verzeichnis ist kein monotone-Arbeitsverzeichnis! + Inventory could not be read Inventar konnte nicht gelesen werden + The inventory could not be read. Maybe another task is still running? Das Inventar konnte nicht gelesen werden. Vielleicht läuft noch ein anderer Prozess? + Loading workspace... Lade Arbeitsbereich... + Ctrl+I Import STRG+I + Ctrl+Q Quit STRG+Q + The chosen directory is no monotone workspace! Das gewählte Verzeichnis ist kein monotone-Arbeitsverzeichnis! + &Import Working Directory... &Importiere Arbeitsbereich + Critical Monotone Error Kritischer monotone-Fehler + Ctrl+I File|Import STRG+I + &View &Ansicht + &Hide ignored files Ignorierte Dateien &verstecken + &Show ignored files Ignorierte Dateien a&nzeigen + &Recent Workspaces &Vorherige Arbeitsbereiche + &Open Workspace Arbeitsbereich &öffnen + &%1 %2 &%1 %2 + No previous workspaces available. Keine vorherigen Arbeitsbereiche verfügbar. + &Workspace &Arbeitsbereich + &Switch revision Auf andere &Revision aktualisieren + &Preferences &Einstellungen + &Key Managment &Schlüsselverwaltung + About &Qt Über &Qt + &Help &Hilfe @@ -213,6 +263,7 @@ Inventory + one level up ein Verzeichnis höher @@ -220,50 +271,62 @@ InventoryItem + File Datei + Status Status + one level up ein Verzeichnis höher + Rename Source Quelle für Umbenennen + Rename Target Ziel für Umbenennen + Added hinzugefügt + Dropped entfernt + Missing fehlend + Patched verändert + Unchanged unverändert + Unknown unbekannt + Ignored ignoriert @@ -271,93 +334,114 @@ InventoryView + &Add &Hinzufügen + Ctrl+A Add + Add to workspace Zum Arbeitsbereich hinzufügen + &Remove En&tfernen + Ctrl+R Remove + Remove from workspace Vom Arbeitsbereich entfernen + &Commit &Einpflegen + Ctrl+C Commit + Commit Einpflegen + I&gnore Datei &ignorieren + Ctrl+G Ignore + Ignore file Datei ignorieren + &Unignore Datei nicht ign&orieren + Ctrl+U Unignore + Unignore file Datei nicht mehr ignorieren + R&evert &Zurücksetzen + Ctrl+E Revert + Revert uncommitted changes Nicht eingepflegte Änderungen verwerfen + Rena&me Um&benennen + Ctrl+M Rename + Rename file Datei umbenennen @@ -365,38 +449,47 @@ KeyManagment + Key Managment Schlüsselverwaltung + Hash Prüfsumme + Name Name + Pub Loc Pfad zu öffentl. Schlüssel + Priv Loc Pfad zu priv. Schlüssel + Generate Erzeugen + Remove Entfernen + OK OK + Cancel Abbrechen @@ -404,10 +497,12 @@ Manifest + Attribute Name Attributsname + Attribute Value Attributswert @@ -415,48 +510,59 @@ Monotone + Monotone not found Monotone nicht gefunden + Couldn't connect to monotone. Have you installed it properly? Konnte Verbindung zu Monotone-Prozess nicht herstellen. Ist das Programm korrekt installiert? + Process exited Prozess beendet + The internal connection to the monotone process was terminated (code %1, status %2) Die interne Verbindung zum Monotone-Prozess wurde beendet (Code %1, Status %2) + Monotone startup error Fehler beim Starten von Monotone + Couldn't startup the monotone process (ProcessError %1). Have you installed it properly? Konnte den monotone-Prozess nicht starten (ProcessError %1). Ist das Programm korrekt installiert? + The connection to the monotone process was terminated (Code %1). Die Verbindung zum monotone-Prozess wurde beendet (Code %1). + Monotone failed to start (Code %1). Have you installed it properly? Monotone konnte nicht gestartet werden (Code %1). Ist das Programm korrekt installiert? + Unable to process command '%1': %2 Das Kommando '%1' konnte nicht abgearbeitet werden: %2 + Monotone failed to start (Code %1). Please configure the path in the Preferences dialog. Monotone konnte nicht gestartet werden (Code %1). Bitte konfigurieren Sie den Pfad im Eintellungsdialog. + The connection to the monotone process was terminated (Code %1). Check your configuration and reload the current workspace afterwards. Die Verbindung zum monotone-Prozess wurde beendet (Code %1). Prüfen Sie Ihre Konfiguration und laden Sie ggf. den Arbeitsbereich danach neu. @@ -464,26 +570,32 @@ korrekt installiert? Preferences + Error Fehler + The entered path is either invalid or points to an older version of monotone. Guitone requires monotone version %1 or later. Der eingegebene Pfad ist entweder ungültig oder zeigt auf eine ältere Version von monotone. Guitone benötigt Version %1 oder neuer. + Notice Hinweis + You need to reload your current workspace or restart guitone to use the new monotone binary. Sie müssen Ihren derzeitigen Arbeitsbereich neu laden oder guitone neu starten, um die neuen Einstellungen zu verwenden. + Choose the monotone executable Wählen Sie die ausführbare Datei von monotone + Binaries (mtn mtn.exe) Ausführbare Dateien (mtn mtn.exe) @@ -491,22 +603,27 @@ korrekt installiert? PreferencesDialog + Preferences Einstellungen + Path to monotone executable Pfad zur ausführbaren Datei von monotone + Browse Durchsuchen + OK OK + Cancel Abbrechen @@ -514,46 +631,57 @@ korrekt installiert? SandboxItem + File Datei + Status Status + Rename Source Quelle für Umbenennen + Rename Target Ziel für Umbenennen + Added hinzugefügt + Dropped entfernt + Missing fehlend + Patched verändert + Unchanged unverändert + Unknown unbekannt + Ignored ignoriert @@ -561,86 +689,107 @@ korrekt installiert? SandboxView + Hide i&gnored items Verstecke i&gnorierte Elemente + File Datei + Folder Verzeichnis + Status Status + ROOT WURZEL + Rename Source Quelle für Umbenennen + Rename Target Ziel für Umbenennen + Added hinzugefügt + Dropped entfernt + Missing fehlend + Patched verändert + Unchanged unverändert + Unknown unbekannt + Ignored ignoriert + Add Hinzufügen + Drop Entfernen + Select Rename Target Ziel für Umbenennung selektieren + Select Rename Source Quelle für Umbenennung selektieren + Revert Änderungen verwerfen + Info Informationen + No functionality yet, sorry! Funktioniert leider noch nicht! @@ -648,6 +797,7 @@ korrekt installiert? Select + Revision ID Revisions-ID @@ -655,54 +805,67 @@ korrekt installiert? SwitchWorkspaceRevision + Switch Workspace Revision Arbeitsbereich auf andere Revision aktualisieren + Find Finden + OK OK + Cancel Abbrechen + Branch Zweig + Tag Marke + Author Autor + Date Datum + Custom Selbstdefiniert + contains beinhaltet + Revision Revision + Revision list could not be read Revisions-Liste konnte nicht gelesen werden + The revision list could not be read. Maybe another task is still running? Die Liste der Revisionen konnte nicht gelesen werden. Eventuell ist noch ein anderer Prozess aktiv? @@ -710,50 +873,62 @@ korrekt installiert? WorkspaceItem + File Datei + Status Status + Rename Source Quelle für Umbenennen + Rename Target Ziel für Umbenennen + Added hinzugefügt + Dropped entfernt + Missing fehlend + Patched verändert + Unchanged unverändert + Unknown unbekannt + Ignored ignoriert + one level up ein Verzeichnis höher @@ -761,62 +936,72 @@ korrekt installiert? WorkspaceView + &Add &Hinzufügen - - - - + &Remove En&tfernen + &Commit &Einpflegen + &Unignore Datei nicht ign&orieren + R&evert &Zurücksetzen + Rena&me Um&benennen + Add to workspace Zum Arbeitsbereich hinzufügen + Remove from workspace Vom Arbeitsbereich entfernen + Commit Einpflegen + I&gnore Datei &ignorieren + Ignore file Datei ignorieren + Unignore file Datei nicht mehr ignorieren + Revert uncommitted changes Nicht eingepflegte Änderungen verwerfen + Rename file Datei umbenennen @@ -824,10 +1009,12 @@ korrekt installiert? main + Unsupported OS Nichtunterstützes Betriebssystem + You're running guitone on MacOS X 10.3 or earlier, but we could only test it on MacOS X 10.4. It may run perfectly fine, but it could also crash horribly. Please give us feedback if something goes wrong. Thanks! Sie starten guitone auf MacOS X 10.3 oder früher, wir konnten die Anwendung aber nur auf MacOS X 10.4 testen. Guitone kann ohne Probleme laufen, aber auch crashen. Bitte teilen Sie uns mit, falls etwas schiefläuft. Vielen Dank! ============================================================ --- guitone/src/model/InventoryProxyModel.cpp 6c7a00ab4949ebcc9d919e053722e2db6679b0a6 +++ guitone/src/model/InventoryProxyModel.cpp e87bd50fd656e93a576f1d6786188ae5ab3da20d @@ -18,7 +18,6 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include "stable.h" #include "InventoryProxyModel.h" #include "InventoryItem.h" ============================================================ --- guitone/src/util/IconProvider.cpp 0dd668940db7738994731e99d18a45b201e4564f +++ guitone/src/util/IconProvider.cpp 373b291301e12a327932f1280dafe27da638e7b6 @@ -18,7 +18,6 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include "stable.h" #include "IconProvider.h" #include "../model/InventoryItem.h" ============================================================ --- guitone/src/view/AttributesView.cpp 7c594a67cea2d436ad1359d518a4ef5b5bfa7c7c +++ guitone/src/view/AttributesView.cpp f248dcfc64ac35f606b7e8da3f7b6f02fcadb857 @@ -19,7 +19,6 @@ ***************************************************************************/ #include "AttributesView.h" -#include "stable.h" #include "../util/Settings.h" AttributesView::AttributesView(QWidget* parent, QString objName) ============================================================ --- guitone/src/view/Splitter.cpp bb5050294e328b9a74cd3d58faeac27094cf3c2d +++ guitone/src/view/Splitter.cpp e339e7a165c79c7d57d4e469c8c003eb6c7c8c7f @@ -19,7 +19,6 @@ ***************************************************************************/ #include "Splitter.h" -#include "stable.h" #include "../util/Settings.h" Splitter::Splitter(QWidget* parent) ============================================================ --- guitone/src/view/TreeView.cpp 3fed528b1ae9f72cfe90380641e9a9f96872f212 +++ guitone/src/view/TreeView.cpp cc5a064468706cc94cf3e1a8a2695c07beb2819b @@ -19,7 +19,6 @@ ***************************************************************************/ #include "TreeView.h" -#include "stable.h" #include "../util/Settings.h" TreeView::TreeView(QWidget* parent) ============================================================ --- guitone/src/view/dialogs/ui_KeyManagment.h e82e9ba78fec73e56da2e9b08b2d64171849f85d +++ guitone/src/view/dialogs/ui_KeyManagment.h ef076eb7a2ef3e3d88e008a296fdd25eed8400b7 @@ -1,3 +1,12 @@ +/******************************************************************************** +** Form generated from reading ui file 'KeyManagment.ui' +** +** Created: Wed Oct 4 16:25:59 2006 +** by: Qt User Interface Compiler version 4.2.0 +** +** WARNING! All changes made in this file will be lost when recompiling ui file! +********************************************************************************/ + #ifndef UI_KEYMANAGMENT_H #define UI_KEYMANAGMENT_H @@ -30,7 +39,6 @@ public: void setupUi(QDialog *KeyManagment) { KeyManagment->setObjectName(QString::fromUtf8("KeyManagment")); - KeyManagment->resize(QSize(587, 433).expandedTo(KeyManagment->minimumSizeHint())); gridLayout = new QGridLayout(KeyManagment); gridLayout->setSpacing(6); gridLayout->setMargin(9); @@ -82,7 +90,13 @@ public: gridLayout->addLayout(hboxLayout, 2, 0, 1, 1); + retranslateUi(KeyManagment); + + QSize size(587, 433); + size = size.expandedTo(KeyManagment->minimumSizeHint()); + KeyManagment->resize(size); + QObject::connect(okButton, SIGNAL(clicked()), KeyManagment, SLOT(accept())); QObject::connect(cancelButton, SIGNAL(clicked()), KeyManagment, SLOT(reject())); @@ -92,8 +106,8 @@ public: void retranslateUi(QDialog *KeyManagment) { KeyManagment->setWindowTitle(QApplication::translate("KeyManagment", "Key Managment", 0, QApplication::UnicodeUTF8)); - tableWidget->clear(); - tableWidget->setColumnCount(4); + if (tableWidget->columnCount() < 4) + tableWidget->setColumnCount(4); QTableWidgetItem *__colItem = new QTableWidgetItem(); __colItem->setText(QApplication::translate("KeyManagment", "Hash", 0, QApplication::UnicodeUTF8)); @@ -110,7 +124,6 @@ public: QTableWidgetItem *__colItem3 = new QTableWidgetItem(); __colItem3->setText(QApplication::translate("KeyManagment", "Priv Loc", 0, QApplication::UnicodeUTF8)); tableWidget->setHorizontalHeaderItem(3, __colItem3); - tableWidget->setRowCount(0); pushButtonGenerate->setText(QApplication::translate("KeyManagment", "Generate", 0, QApplication::UnicodeUTF8)); pushButtonRemove->setText(QApplication::translate("KeyManagment", "Remove", 0, QApplication::UnicodeUTF8)); okButton->setText(QApplication::translate("KeyManagment", "OK", 0, QApplication::UnicodeUTF8)); ============================================================ --- guitone/src/view/dialogs/ui_preferences.h 7bf70ad1a88dcebe0fc90dc4eb0a309463676980 +++ guitone/src/view/dialogs/ui_preferences.h 241e018833bdf465c7cce8a41e7c3a0980d1fcb1 @@ -1,3 +1,12 @@ +/******************************************************************************** +** Form generated from reading ui file 'preferences.ui' +** +** Created: Wed Oct 4 16:25:59 2006 +** by: Qt User Interface Compiler version 4.2.0 +** +** WARNING! All changes made in this file will be lost when recompiling ui file! +********************************************************************************/ + #ifndef UI_PREFERENCES_H #define UI_PREFERENCES_H @@ -31,7 +40,6 @@ public: void setupUi(QDialog *PreferencesDialog) { PreferencesDialog->setObjectName(QString::fromUtf8("PreferencesDialog")); - PreferencesDialog->resize(QSize(404, 140).expandedTo(PreferencesDialog->minimumSizeHint())); QSizePolicy sizePolicy(static_cast(3), static_cast(0)); sizePolicy.setHorizontalStretch(0); sizePolicy.setVerticalStretch(0); @@ -104,7 +112,13 @@ public: QWidget::setTabOrder(mtnExecutablePath, selectMtnExecutable); QWidget::setTabOrder(selectMtnExecutable, okButton); QWidget::setTabOrder(okButton, cancelButton); + retranslateUi(PreferencesDialog); + + QSize size(404, 140); + size = size.expandedTo(PreferencesDialog->minimumSizeHint()); + PreferencesDialog->resize(size); + QObject::connect(okButton, SIGNAL(clicked()), PreferencesDialog, SLOT(accept())); QObject::connect(cancelButton, SIGNAL(clicked()), PreferencesDialog, SLOT(reject())); ============================================================ --- guitone/src/view/dialogs/ui_switch_workspace.h 9ea0d34e428e64e6f73521babeb3be52b12becd1 +++ guitone/src/view/dialogs/ui_switch_workspace.h 7f800f9ff1683e12662b86fc5a9ad5188368b4a0 @@ -1,3 +1,12 @@ +/******************************************************************************** +** Form generated from reading ui file 'switch_workspace.ui' +** +** Created: Wed Oct 4 16:25:59 2006 +** by: Qt User Interface Compiler version 4.2.0 +** +** WARNING! All changes made in this file will be lost when recompiling ui file! +********************************************************************************/ + #ifndef UI_SWITCH_WORKSPACE_H #define UI_SWITCH_WORKSPACE_H @@ -37,7 +46,6 @@ public: void setupUi(QDialog *SwitchWorkspaceRevision) { SwitchWorkspaceRevision->setObjectName(QString::fromUtf8("SwitchWorkspaceRevision")); - SwitchWorkspaceRevision->resize(QSize(622, 421).expandedTo(SwitchWorkspaceRevision->minimumSizeHint())); vboxLayout = new QVBoxLayout(SwitchWorkspaceRevision); vboxLayout->setSpacing(6); vboxLayout->setMargin(9); @@ -123,7 +131,13 @@ public: QWidget::setTabOrder(revisionList, certList); QWidget::setTabOrder(certList, okButton); QWidget::setTabOrder(okButton, cancelButton); + retranslateUi(SwitchWorkspaceRevision); + + QSize size(622, 421); + size = size.expandedTo(SwitchWorkspaceRevision->minimumSizeHint()); + SwitchWorkspaceRevision->resize(size); + QObject::connect(okButton, SIGNAL(clicked()), SwitchWorkspaceRevision, SLOT(accept())); QObject::connect(cancelButton, SIGNAL(clicked()), SwitchWorkspaceRevision, SLOT(reject())); ============================================================ --- guitone.pro 0c104884af75f7cd2bfc2e950dc56885da79301e +++ guitone.pro d25442e228ae59d846371735ed708838c8d3bcf9 @@ -1,73 +1,4 @@ -CONFIG += qt debug precompile_header -HEADERS += src/view/Guitone.h \ - src/view/TreeView.h \ - src/view/Splitter.h \ - src/view/InventoryView.h \ - src/view/AttributesView.h \ - src/view/dialogs/SwitchWorkspaceRevision.h \ - src/view/dialogs/Preferences.h \ - src/view/dialogs/KeyManagment.h \ - src/monotone/Monotone.h \ - src/model/AutomateCommand.h \ - src/model/Inventory.h \ - src/model/InventoryItem.h \ - src/model/InventoryProxyModel.h \ - src/model/Attributes.h \ - src/model/Select.h \ - src/model/Certs.h \ - src/util/IconProvider.h \ - src/util/StanzaParser.h \ - src/util/Settings.h -SOURCES += src/view/Guitone.cpp \ - src/view/TreeView.cpp \ - src/view/Splitter.cpp \ - src/view/InventoryView.cpp \ - src/view/AttributesView.cpp \ - src/view/dialogs/SwitchWorkspaceRevision.cpp \ - src/view/dialogs/Preferences.cpp \ - src/view/dialogs/KeyManagment.cpp \ - src/monotone/Monotone.cpp \ - src/model/AutomateCommand.cpp \ - src/model/Inventory.cpp \ - src/model/InventoryItem.cpp \ - src/model/InventoryProxyModel.cpp \ - src/model/Attributes.cpp \ - src/model/Select.cpp \ - src/model/Certs.cpp \ - src/util/IconProvider.cpp \ - src/util/StanzaParser.cpp \ - src/util/Settings.cpp \ - src/main.cpp -FORMS += res/dialogs/switch_workspace.ui \ - res/dialogs/preferences.ui \ - res/dialogs/KeyManagment.ui -UI_DIR = src/view/dialogs -TEMPLATE = app -DEPENDPATH += src -INCLUDEPATH += . src -OBJECTS_DIR = tmp -MOC_DIR = tmp -DESTDIR = bin -TRANSLATIONS = res/i18n/guitone_de.ts -RESOURCES = res/guitone.qrc -RCC_DIR = tmp -PRECOMPILED_HEADER = src/stable.h +TEMPLATE = subdirs +SUBDIRS = guitone \ + libs -macx { - # copy i18n resources into the final app bundle - QMAKE_POST_LINK = cp -R res/osx/Resources bin/guitone.app/Contents - - # osx application icon - ICON = res/osx/guitone.icns - - # set this to either ppc or i386 or both if you want to create - # a PowerPC, x86 or Universal OSX binary - debug { - CONFIG += ppc - } - release { - CONFIG += ppc - } - # path to the OSX universal SDK - QMAKE_MAC_SDK = /Developer/SDKs/MacOSX10.4u.sdk -}