diff --git a/CMakeLists.txt b/CMakeLists.txt index b0a130711..9821a10e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,363 +1,241 @@ +cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) + project(umbrello) # KDE Application Version, managed by release script set (KDE_APPLICATIONS_VERSION_MAJOR "19") set (KDE_APPLICATIONS_VERSION_MINOR "07") set (KDE_APPLICATIONS_VERSION_MICRO "70") set(UMBRELLO_VERSION_MAJOR "2") MATH(EXPR UMBRELLO_VERSION_MINOR "30-${KDE_APPLICATIONS_VERSION_MINOR}") set(UMBRELLO_VERSION_PATCH ${KDE_APPLICATIONS_VERSION_MICRO}) option(BUILD_ICONS "Create icons from svg source" OFF) option(BUILD_CURSOR_ICONS "Create cursor icons from svg source" OFF) option(BUILD_ICONS_INTO_SIZE_RELATED_DIRS "place icons into separate directories (for debugging purpose)" OFF) option(BUILD_KF5 "Build for KDE Frameworks 5" ON) # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) include(Macros) set(CMAKE_AUTORCC ON) if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-delete-null-pointer-checks") # TODO: after removing kdelibs4support this could also be removed set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif() -find_package(KDevelop-PG-Qt) - if(NOT BUILD_KF5) - cmake_minimum_required(VERSION 2.8 FATAL_ERROR) - + set(APP_SUFFIX) + set(LIB_PREFIX Qt4::Qt) set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) - find_package(Qt4 4.4.3 REQUIRED QtCore QtGui QtXml QtTest QtWebKit) - - # search packages used by KDE - find_package(KDE4 REQUIRED) - include(KDE4Defaults) - include(MacroLibrary) - - # The FindKDE4.cmake module sets _KDE4_PLATFORM_DEFINITIONS with - # definitions like _GNU_SOURCE that are needed on each platform. - set(CMAKE_REQUIRED_DEFINITIONS ${_KDE4_PLATFORM_DEFINITIONS} -DQT_STRICT_ITERATORS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - - add_definitions ( - ${KDE4_DEFINITIONS} - ) - - include_directories( - ${KDE4_INCLUDES} - ) - - if(KDE4_BUILD_TESTS) - enable_testing() - set(BUILD_UNITTESTS 1) - endif() - - macro(ki18n_wrap_ui) - kde4_add_ui_files(${ARGN}) - endmacro(ki18n_wrap_ui) - - macro(kconfig_add_kcfg_files) - kde4_add_kcfg_files(${ARGN}) - endmacro(kconfig_add_kcfg_files) - - macro(ecm_optional_add_subdirectory) - add_subdirectory(${ARGN}) - endmacro(ecm_optional_add_subdirectory) - - macro(ecm_add_test) - set(sources) - set(libs) - set(name_prefix) - set(test_name) - set(mode 0) - set(guimode "NOGUI") - foreach(a ${ARGN}) - if(a STREQUAL "LINK_LIBRARIES") - set(mode 1) - elseif(a STREQUAL "NAME_PREFIX") - set(mode 2) - elseif(a STREQUAL "GUI") - set(guimode "GUI") - set(mode 3) - elseif(a STREQUAL "TEST_NAME") - set(mode 4) - elseif (mode EQUAL 0) - list(APPEND sources ${a}) - elseif(mode EQUAL 1) - list(APPEND libs ${a}) - elseif(mode EQUAL 2) - set(name_prefix ${a}) - elseif(mode EQUAL 4) - set(test_name ${a}) - endif() - endforeach(a) - - set(targetname ${test_name}) - if(name_prefix) - set(testname ${name_prefix}-${targetname}) - else() - set(testname ${targetname}) - endif() - kde4_add_unit_test(${targetname} TESTNAME ${testname} ${guimode} ${sources}) - target_link_libraries(${targetname} ${libs}) - endmacro(ecm_add_test) - - macro(ecm_add_executable) - kde4_add_executable(${ARGN}) - endmacro(ecm_add_executable) - - macro(ecm_mark_nongui_executable) - foreach(_target ${ARGN}) - set_target_properties(${_target} - PROPERTIES - WIN32_EXECUTABLE FALSE - MACOSX_BUNDLE FALSE - ) - endforeach() - endmacro(ecm_mark_nongui_executable) - - macro(kdoctools_create_handbook) - set(KDOCTOOLS_CUSTOMIZATION_DIR "${KDE4_DATA_INSTALL_DIR}/ksgmltools2/customization") - set(KDEX_DTD ${KDE4_DATA_DIR}/ksgmltools2/customization/dtd/kdex.dtd) - set(kdedbx45_dtd " - - %kdexDTD; - ") - set(CUSTOM_DTD ${CMAKE_CURRENT_SOURCE_DIR}/dtd/kdedbx45.dtd) - if (NOT EXISTS ${CUSTOM_DTD}) - file(WRITE ${CUSTOM_DTD} "${kdedbx45_dtd}") - endif() - kde4_create_handbook(${ARGN}) - endmacro() - if(NOT DISABLE_PHP_IMPORT) - find_package(KDevelop-PG-Qt) - find_package(KDevPlatform) - if ("${KDevPlatform_VERSION_MAJOR}" STREQUAL "5") - message(FATAL_ERROR "Could not compile with KF5 based kdevplatform. Please uninstall or specify -DDISABLE_PHP_IMPORT=1") - endif() - endif() - if(KDEVPGQT_FOUND AND KDEVPLATFORM_FOUND) - include_directories( - ${KDEVPGQT_INCLUDE_DIR} - ${KDEVPLATFORM_INCLUDE_DIR} - ${CMAKE_SOURCE_DIR}/lib/kdev4-php/parser - ${CMAKE_BINARY_DIR}/lib/kdev4-php/parser - ) - set(NO_INSTALL 1) - set(BUILD_PARSER_ONLY 1) - set(BUILD_PHP_IMPORT 1) - add_definitions( - -DKDEVPHPPARSER_EXPORT= - -DENABLE_PHP_IMPORT - ) - add_subdirectory(lib/kdev4-php) - endif() - - macro_display_feature_log() - KDE4_NO_ENABLE_FINAL(umbrello) - set(UMBRELLO_DATA_INSTALL_DIR ${DATA_INSTALL_DIR}/umbrello) + include(ECMKDE4Macros) + set(QT_MIN_VERSION "4.8.0") + set(KDEV_MIN_VERSION 1.5.2) + set(KDEV_SOURCE_DIR lib/kdev4-php) + set(KDEV_COMPONENTS) else() - cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) - + set(APP_SUFFIX 5) + set(LIB_PREFIX Qt5::) # we need some parts of the ECM CMake helpers find_package(ECM 1.1.0 REQUIRED NO_MODULE) list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) include(KDEInstallDirs) include(KDECompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) include(FeatureSummary) include(ECMInstallIcons) include(ECMSetupVersion) include(ECMOptionalAddSubdirectory) include(ECMAddAppIcon) include(ECMAddTests) - - # search packages used by Qt set(QT_MIN_VERSION "5.2.0") - find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS - Core - Gui - PrintSupport - Svg - Test - Widgets - Xml - WebKitWidgets - ) + set(KDEV_MIN_VERSION 5.1.2) + set(KDEV_SOURCE_DIR lib/kdev5-php) + set(KDEV_COMPONENTS KDev::Interfaces KDev::Language KDev::Tests) +endif() + +# search packages used by Qt +find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS + Core + Gui + PrintSupport + Svg + Test + Widgets + Xml + WebKitWidgets +) + +# search packages used by KDE +find_package(KF5 REQUIRED COMPONENTS + Archive + Completion + Config + CoreAddons + Crash + DocTools + I18n + IconThemes + KDELibs4Support + KIO + TextEditor + WidgetsAddons + WindowSystem + XmlGui +) - # search packages used by KDE - find_package(KF5 REQUIRED COMPONENTS - Archive - Completion - Config - CoreAddons - Crash - DocTools - I18n - IconThemes - KDELibs4Support - KIO - TextEditor - WidgetsAddons - WindowSystem - XmlGui +if(NOT DISABLE_PHP_IMPORT) + find_package(KDevelop-PG-Qt) + find_package(KDevPlatform ${KDEV_MIN_VERSION} COMPONENTS ${KDEV_COMPONENTS}) +endif() +if(BUILD_KF5 AND NOT TARGET KDev::Tests) + message(STATUS "Could not find required KDevPlatform component KDev::Tests - disabling php import support") + set(KDEVPLATFORM_FOUND 0) +endif() +if(KDEVPGQT_FOUND AND KDEVPLATFORM_FOUND) + include_directories( + ${KDEVPGQT_INCLUDE_DIR} + ${KDEVPLATFORM_INCLUDE_DIR} + ${CMAKE_SOURCE_DIR}/${KDEV_SOURCE_DIR}/parser + ${CMAKE_BINARY_DIR}/${KDEV_SOURCE_DIR}/parser ) + set(NO_INSTALL 1) + set(BUILD_PARSER_ONLY 1) + set(BUILD_PHP_IMPORT 1) + add_definitions( + -DKDEVPHPPARSER_EXPORT= + -DENABLE_PHP_IMPORT + ) + add_subdirectory(${KDEV_SOURCE_DIR}) +endif() - macro(ecm_add_executable) - add_executable(${ARGN}) - endmacro(ecm_add_executable) +set(UMBRELLO_DATA_INSTALL_DIR ${DATA_INSTALL_DIR}/umbrello${APP_SUFFIX}) +if(NOT BUILD_KF5) + macro_display_feature_log() + KDE4_NO_ENABLE_FINAL(umbrello) +else() set(BUILD_UNITTESTS 1) - set(UMBRELLO_DATA_INSTALL_DIR ${DATA_INSTALL_DIR}/umbrello5) ki18n_install(po) kdoctools_install(po) - - find_package(KDevPlatform "5.1.2" COMPONENTS - KDev::Interfaces - KDev::Language - KDev::Tests - ) - if(KDEVPGQT_FOUND AND KDEVPLATFORM_FOUND AND TARGET KDev::Tests) - include_directories( - ${KDEVPGQT_INCLUDE_DIR} - ${KDEVPLATFORM_INCLUDE_DIR} - ${CMAKE_SOURCE_DIR}/lib/kdev5-php/parser - ${CMAKE_BINARY_DIR}/lib/kdev5-php/parser - ) - set(NO_INSTALL 1) - set(BUILD_PARSER_ONLY 1) - set(BUILD_PHP_IMPORT 1) - add_definitions( - -DKDEVPHPPARSER_EXPORT= - -DENABLE_PHP_IMPORT - ) - add_subdirectory(lib/kdev5-php) - elseif(NOT TARGET KDev::Tests) - message(STATUS "Could not find required KDevPlatform component KDev::Tests - disabling php import support") - endif() endif() if(POLICY CMP0071) cmake_policy(SET CMP0071 OLD) endif() # use some compile flags add_definitions( -DQT_NO_SIGNAL_SLOTS_KEYWORDS -DQT_NO_URL_CAST_FROM_STRING ) # set default umbrello version # umbrello version could be overridden by cmake command line using -DUMBRELLO_VERSION_STRING=major.minor.patch if(NOT UMBRELLO_VERSION_STRING) set(UMBRELLO_VERSION_STRING "${UMBRELLO_VERSION_MAJOR}.${UMBRELLO_VERSION_MINOR}.${UMBRELLO_VERSION_PATCH}") if(EXISTS ${CMAKE_SOURCE_DIR}/.git) execute_process( COMMAND git rev-parse --short HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE _hash ) if(_hash) string(REPLACE "\n" "" hash ${_hash}) set(UMBRELLO_VERSION_STRING "${UMBRELLO_VERSION_STRING}-${hash}") endif() endif() endif() message(STATUS "Using umbrello version ${UMBRELLO_VERSION_STRING}") add_definitions(-DUMBRELLO_VERSION_STRING="${UMBRELLO_VERSION_STRING}") message(STATUS "Using automoc4 version ${AUTOMOC4_VERSION}") message(STATUS "Using cmake version ${CMAKE_VERSION}") -if (BUILD_KF5) - set(QTVERSION ${Qt5Widgets_VERSION}) -endif() message(STATUS "Using Qt version ${QTVERSION}") find_package(LibXslt) set_package_properties(LibXslt PROPERTIES DESCRIPTION "A library to transform XMLfiles into other XML files." URL "http://xmlsoft.org/XSLT" TYPE REQUIRED) find_package(LibXml2) set_package_properties(LibXml2 PROPERTIES DESCRIPTION "Libraries used to develop XML applications." URL "http://xmlsoft.org" TYPE REQUIRED) include_directories( ${CMAKE_BINARY_DIR} ) # # Unstable features should not be enabled in stable branches # This macro limits unstable feature to development branches # by only adding -DENABLE_ to the compile command when # the patch level is >= 70 which includes releases from master # beta and rc releases. On cmake configure time a related status # note is displayed. # # syntax: add_unstable_feature() # # In code wrap feature related code with # # #ifdef ENABLE_ # # #endif # macro(add_unstable_feature name) if(UMBRELLO_VERSION_PATCH GREATER 69) add_definitions(-DENABLE_${name}) set(ENABLE_${name} 1) message(STATUS "Enable unstable feature ${name} - use '#ifdef ENABLE_${name}' in related code") else() set(ENABLE_${name} 0) message(STATUS "Disable unstable feature ${name}") endif() endmacro(add_unstable_feature) add_unstable_feature(WIDGET_SHOW_DOC) # show documentation in classes ticket xxx add_unstable_feature(NEW_CODE_GENERATORS) # new c++ code generator add_unstable_feature(UML_OBJECTS_WINDOW) # objects dock window add_unstable_feature(XMIRESOLUTION) # see https://bugs.kde.org/show_bug.cgi?id=90103 # Current object diagram implementation does not follow UML 1.4 standard # because of using umbrello specific XMI tag (UML:InstanceAttribute). add_unstable_feature(OBJECT_DIAGRAM) # see https://bugs.kde.org/show_bug.cgi?id=123633 configure_file(Doxyfile ${CMAKE_BINARY_DIR}/Doxyfile) find_program(DOXYGEN_EXECUTABLE doxygen) if(DOXYGEN_EXECUTABLE) add_custom_target(apidoc COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile ) endif() if(LIBXSLT_FOUND AND LIBXML2_FOUND) add_subdirectory(umbrello) add_subdirectory(doc) add_subdirectory(tools) endif(LIBXSLT_FOUND AND LIBXML2_FOUND) add_subdirectory(maintainer) # for automatic unit tests if(BUILD_UNITTESTS) ecm_optional_add_subdirectory(unittests) endif() feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/cmake/modules/ECMKDE4Macros.cmake b/cmake/modules/ECMKDE4Macros.cmake new file mode 100644 index 000000000..5acb536d8 --- /dev/null +++ b/cmake/modules/ECMKDE4Macros.cmake @@ -0,0 +1,128 @@ +# +# ecm compatible build system wrapper for KDE4 +# + +macro(ki18n_wrap_ui) + kde4_add_ui_files(${ARGN}) +endmacro(ki18n_wrap_ui) + +macro(kconfig_add_kcfg_files) + kde4_add_kcfg_files(${ARGN}) +endmacro(kconfig_add_kcfg_files) + +macro(ecm_optional_add_subdirectory) + add_subdirectory(${ARGN}) +endmacro(ecm_optional_add_subdirectory) + +macro(ecm_add_test) + set(sources) + set(libs) + set(name_prefix) + set(test_name) + set(mode 0) + set(guimode "NOGUI") + foreach(a ${ARGN}) + if(a STREQUAL "LINK_LIBRARIES") + set(mode 1) + elseif(a STREQUAL "NAME_PREFIX") + set(mode 2) + elseif(a STREQUAL "GUI") + set(guimode "GUI") + set(mode 3) + elseif(a STREQUAL "TEST_NAME") + set(mode 4) + elseif (mode EQUAL 0) + list(APPEND sources ${a}) + elseif(mode EQUAL 1) + list(APPEND libs ${a}) + elseif(mode EQUAL 2) + set(name_prefix ${a}) + elseif(mode EQUAL 4) + set(test_name ${a}) + endif() + endforeach(a) + + set(targetname ${test_name}) + if(name_prefix) + set(testname ${name_prefix}-${targetname}) + else() + set(testname ${targetname}) + endif() + kde4_add_unit_test(${targetname} TESTNAME ${testname} ${guimode} ${sources}) + target_link_libraries(${targetname} ${libs}) +endmacro(ecm_add_test) + +macro(add_executable) + # avoid recursive loops + math(EXPR in_add_executable "${in_add_executable} + 1") + if(${in_find_package} OR ${in_add_executable} GREATER 1) + _add_executable(${ARGV}) + else() + kde4_add_executable(${ARGV}) + endif() + math(EXPR in_add_executable "${in_add_executable} - 1") +endmacro(add_executable) + +macro(ecm_mark_nongui_executable) + foreach(_target ${ARGN}) + set_target_properties(${_target} + PROPERTIES + WIN32_EXECUTABLE FALSE + MACOSX_BUNDLE FALSE + ) + endforeach() +endmacro(ecm_mark_nongui_executable) + +macro(kdoctools_create_handbook) + set(KDOCTOOLS_CUSTOMIZATION_DIR "${KDE4_DATA_INSTALL_DIR}/ksgmltools2/customization") + set(KDEX_DTD ${KDE4_DATA_DIR}/ksgmltools2/customization/dtd/kdex.dtd) + set(kdedbx45_dtd " + +%kdexDTD; +") + set(CUSTOM_DTD ${CMAKE_CURRENT_SOURCE_DIR}/dtd/kdedbx45.dtd) + if (NOT EXISTS ${CUSTOM_DTD}) + file(WRITE ${CUSTOM_DTD} "${kdedbx45_dtd}") + endif() + kde4_create_handbook(${ARGN}) +endmacro() + +macro(ecm_install_icons) + kde4_install_icons(${ICON_INSTALL_DIR}) +endmacro() + + +macro(find_package package) + # avoid recursive loops + math(EXPR in_find_package "${in_find_package} + 1") + #message("-- ${ARGV} --") + if("${package}" MATCHES "^(Qt5)") + #message("-- replaced by finding Qt4 --") + _find_package(Qt4 4.4.3 REQUIRED QtCore QtGui QtXml QtTest QtWebKit) + elseif("${package}" MATCHES "^(KF5)$") + #message("-- replaced by finding KDE4 --") + _find_package(KDE4 REQUIRED) + include(KDE4Defaults) + include(MacroLibrary) + + # The FindKDE4.cmake module sets _KDE4_PLATFORM_DEFINITIONS with + # definitions like _GNU_SOURCE that are needed on each platform. + set(CMAKE_REQUIRED_DEFINITIONS ${_KDE4_PLATFORM_DEFINITIONS} -DQT_STRICT_ITERATORS) + add_definitions (${KDE4_DEFINITIONS}) + include_directories(${KDE4_INCLUDES}) + if(KDE4_BUILD_TESTS) + enable_testing() + set(BUILD_UNITTESTS 1) + endif() + elseif("${package}" MATCHES "^(KDevPlatform)$") + _find_package(${ARGV}) + if ("${KDevPlatform_VERSION_MAJOR}" STREQUAL "5") + message(FATAL_ERROR "Could not compile with KF5 based kdevplatform. Please uninstall or specify -DDISABLE_PHP_IMPORT=1") + endif() + else() + _find_package(${ARGV}) + endif() + math(EXPR in_find_package "${in_find_package} - 1") +endmacro() diff --git a/maintainer/CMakeLists.txt b/maintainer/CMakeLists.txt index c2c1b76f3..5f622c1c8 100644 --- a/maintainer/CMakeLists.txt +++ b/maintainer/CMakeLists.txt @@ -1,7 +1,7 @@ # to regenerate icons if(BUILD_ICONS OR BUILD_CURSOR_ICONS) set(svg2png_SRCS svg2png.cpp) - ecm_add_executable(svg2png ${svg2png_SRCS}) + add_executable(svg2png ${svg2png_SRCS}) target_link_libraries(svg2png ${QT_QTXML_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTSVG_LIBRARY}) endif() diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index d3a4a5a3f..ef480758c 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,29 +1,21 @@ -if(NOT BUILD_KF5) - set(LIBS Qt4::QtXml Qt4::QtCore) -else() - set(LIBS Qt5::Xml Qt5::Core) -endif() +set(LIBS ${LIB_PREFIX}Xml ${LIB_PREFIX}Core) set(po2xmi_SRCS po2xmi.cpp shared.cpp) -ecm_add_executable(po2xmi ${po2xmi_SRCS}) +add_executable(po2xmi ${po2xmi_SRCS}) target_link_libraries(po2xmi ${LIBS}) -if(BUILD_KF5) - set_target_properties(po2xmi PROPERTIES OUTPUT_NAME po2xmi5) -endif() +set_target_properties(po2xmi PROPERTIES OUTPUT_NAME po2xmi${APP_SUFFIX}) install(TARGETS po2xmi ${INSTALL_TARGETS_DEFAULT_ARGS}) set(xmi2pot_SRCS xmi2pot.cpp shared.cpp) -ecm_add_executable(xmi2pot ${xmi2pot_SRCS}) +add_executable(xmi2pot ${xmi2pot_SRCS}) target_link_libraries(xmi2pot ${LIBS}) -if(BUILD_KF5) - set_target_properties(xmi2pot PROPERTIES OUTPUT_NAME xmi2pot5) -endif() +set_target_properties(xmi2pot PROPERTIES OUTPUT_NAME xmi2pot${APP_SUFFIX}) install(TARGETS xmi2pot ${INSTALL_TARGETS_DEFAULT_ARGS}) ecm_mark_nongui_executable(po2xmi xmi2pot) diff --git a/umbrello/CMakeLists.txt b/umbrello/CMakeLists.txt index 90c68876d..82e39959d 100644 --- a/umbrello/CMakeLists.txt +++ b/umbrello/CMakeLists.txt @@ -1,678 +1,679 @@ add_subdirectory( headings ) if(ENABLE_OBJECT_DIAGRAM) set(ACTION_NEW_OBJECT_DIAGRAM "") endif() configure_file(umbrelloui.rc.cmake ${CMAKE_CURRENT_BINARY_DIR}/umbrelloui.rc @ONLY) if(BUILD_KF5) configure_file(ui.qrc.cmake ${CMAKE_CURRENT_BINARY_DIR}/ui.qrc @ONLY) endif() ########### set variables ############# # php import support requires kdevplatform and kdev-php # which does not compile without NO_CAST_XX_ASCII if(NOT BUILD_PHP_IMPORT) add_definitions(-DQT_NO_CAST_TO_ASCII) add_definitions(-DQT_NO_CAST_FROM_ASCII) endif() # Some definitions for experimental code or debugging # TODO migrate debug settings to DEBUG_REGISTER macro #add_definitions(-DXMI_FLAT_PACKAGES) # umlobject #add_definitions(-DDEBUG_LVITEM_INSERTION_ORDER) # umllistviewitem #add_definitions(-DTRY_BUGFIX_120682) # model_utils #add_definitions(-DVERBOSE_DEBUGGING) # listpopupmenu, association, petaltree2uml, # umlobject, umldoc, classifierlistpage if(UNIX) add_definitions(-D_GLIBCXX_PERMIT_BACKWARD_HASH) endif() add_definitions(-DCMAKE_BINARY_DIR="${CMAKE_BINARY_DIR}") add_definitions(-DDOCGENERATORS_DIR="${CMAKE_SOURCE_DIR}/umbrello/docgenerators") add_definitions(-DUMBRELLOUI_RC="${CMAKE_CURRENT_BINARY_DIR}/umbrelloui.rc") include_directories( ${LIBXML2_INCLUDE_DIR} ${LIBXSLT_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/ ${CMAKE_CURRENT_SOURCE_DIR}/clipboard/ ${CMAKE_CURRENT_SOURCE_DIR}/cmds ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/ada/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/as/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/cpp/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/csharp/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/d/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/idl/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/java/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/js/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/pascal/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/perl/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/php/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/python/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/ruby/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/sql/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/tcl/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/vala/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/xml/ ${CMAKE_CURRENT_SOURCE_DIR}/codegenwizard/ ${CMAKE_CURRENT_SOURCE_DIR}/codeimport/ ${CMAKE_CURRENT_SOURCE_DIR}/codeimport/csharp/ ${CMAKE_CURRENT_SOURCE_DIR}/codeimpwizard/ ${CMAKE_CURRENT_SOURCE_DIR}/debug/ ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/ ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/pages/ ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/widgets/ ${CMAKE_CURRENT_SOURCE_DIR}/docgenerators/ ${CMAKE_CURRENT_SOURCE_DIR}/finder/ ${CMAKE_CURRENT_SOURCE_DIR}/refactoring/ ${CMAKE_CURRENT_SOURCE_DIR}/uml1model/ ${CMAKE_CURRENT_SOURCE_DIR}/umlwidgets/ ${CMAKE_CURRENT_SOURCE_DIR}/menus ${CMAKE_SOURCE_DIR}/lib/cppparser/ ${CMAKE_SOURCE_DIR}/lib/interfaces/ ) set(libdebug_SRCS debug/debug_utils.cpp ) set(libcodegenerator_SRCS codegenerators/advancedcodegenerator.cpp codegenerators/classifiercodedocument.cpp codegenerators/codeaccessormethod.cpp codegenerators/codeblock.cpp codegenerators/codeblockwithcomments.cpp codegenerators/codeclassfield.cpp codegenerators/codeclassfielddeclarationblock.cpp codegenerators/codecomment.cpp codegenerators/codedocument.cpp codegenerators/codegenerationpolicy.cpp codegenerators/codegenerator.cpp codegenerators/codegenfactory.cpp codegenerators/codegenobjectwithtextblocks.cpp codegenerators/codegenpolicyext.cpp codegenerators/codegen_utils.cpp codegenerators/codemethodblock.cpp codegenerators/codeoperation.cpp codegenerators/codeparameter.cpp codegenerators/ada/adawriter.cpp codegenerators/as/aswriter.cpp codegenerators/cpp/cppcodeclassfield.cpp codegenerators/cpp/cppcodecomment.cpp codegenerators/cpp/cppcodedocumentation.cpp codegenerators/cpp/cppcodegenerationform.cpp codegenerators/cpp/cppcodegenerationpolicy.cpp codegenerators/cpp/cppcodegenerationpolicypage.cpp codegenerators/cpp/cppcodegenerator.cpp codegenerators/cpp/cppheaderclassdeclarationblock.cpp codegenerators/cpp/cppheadercodeaccessormethod.cpp codegenerators/cpp/cppheadercodeclassfielddeclarationblock.cpp codegenerators/cpp/cppheadercodedocument.cpp codegenerators/cpp/cppheadercodeoperation.cpp codegenerators/cpp/cppmakecodedocument.cpp codegenerators/cpp/cppsourcecodeaccessormethod.cpp codegenerators/cpp/cppsourcecodeclassfielddeclarationblock.cpp codegenerators/cpp/cppsourcecodedocument.cpp codegenerators/cpp/cppsourcecodeoperation.cpp codegenerators/cpp/cppwriter.cpp codegenerators/csharp/csharpwriter.cpp codegenerators/d/dclassdeclarationblock.cpp codegenerators/d/dclassifiercodedocument.cpp codegenerators/d/dcodeaccessormethod.cpp codegenerators/d/dcodeclassfield.cpp codegenerators/d/dcodeclassfielddeclarationblock.cpp codegenerators/d/dcodecomment.cpp codegenerators/d/dcodedocumentation.cpp codegenerators/d/dcodegenerationpolicy.cpp codegenerators/d/dcodegenerationpolicypage.cpp codegenerators/d/dcodegenerator.cpp codegenerators/d/dcodeoperation.cpp codegenerators/d/dwriter.cpp codegenerators/hierarchicalcodeblock.cpp codegenerators/idl/idlwriter.cpp codegenerators/java/javaantcodedocument.cpp codegenerators/java/javaclassdeclarationblock.cpp codegenerators/java/javaclassifiercodedocument.cpp codegenerators/java/javacodeaccessormethod.cpp codegenerators/java/javacodeclassfield.cpp codegenerators/java/javacodeclassfielddeclarationblock.cpp codegenerators/java/javacodecomment.cpp codegenerators/java/javacodedocumentation.cpp codegenerators/java/javacodegenerationpolicy.cpp codegenerators/java/javacodegenerationpolicypage.cpp codegenerators/java/javacodegenerator.cpp codegenerators/java/javacodeoperation.cpp codegenerators/java/javawriter.cpp codegenerators/js/jswriter.cpp codegenerators/ownedcodeblock.cpp codegenerators/ownedhierarchicalcodeblock.cpp codegenerators/pascal/pascalwriter.cpp codegenerators/perl/perlwriter.cpp codegenerators/php/php5writer.cpp codegenerators/php/phpwriter.cpp codegenerators/python/pythonwriter.cpp codegenerators/ruby/rubyclassdeclarationblock.cpp codegenerators/ruby/rubyclassifiercodedocument.cpp codegenerators/ruby/rubycodeaccessormethod.cpp codegenerators/ruby/rubycodeclassfield.cpp codegenerators/ruby/rubycodeclassfielddeclarationblock.cpp codegenerators/ruby/rubycodecomment.cpp codegenerators/ruby/rubycodedocumentation.cpp codegenerators/ruby/rubycodegenerationpolicy.cpp codegenerators/ruby/rubycodegenerationpolicypage.cpp codegenerators/ruby/rubycodegenerator.cpp codegenerators/ruby/rubycodeoperation.cpp codegenerators/ruby/rubywriter.cpp codegenerators/simplecodegenerator.cpp codegenerators/sql/mysqlwriter.cpp codegenerators/sql/postgresqlwriter.cpp codegenerators/sql/sqlwriter.cpp codegenerators/tcl/tclwriter.cpp codegenerators/textblock.cpp codegenerators/vala/valawriter.cpp codegenerators/xml/xmlcodecomment.cpp codegenerators/xml/xmlelementcodeblock.cpp codegenerators/xml/xmlschemawriter.cpp ) ki18n_wrap_ui( libcodegenerator_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/cpp/cppcodegenerationformbase.ui ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/d/dcodegenerationformbase.ui ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/java/javacodegenerationformbase.ui ${CMAKE_CURRENT_SOURCE_DIR}/codegenerators/ruby/rubycodegenerationformbase.ui ) set(libdocgenerator_SRCS docgenerators/docbook2xhtmlgeneratorjob.cpp docgenerators/docbookgenerator.cpp docgenerators/docbookgeneratorjob.cpp docgenerators/xhtmlgenerator.cpp ) set(libdialogs_SRCS dialogs/activitydialog.cpp dialogs/associationpropertiesdialog.cpp dialogs/classpropertiesdialog.cpp dialogs/classwizard.cpp dialogs/codeeditor.cpp dialogs/codetextedit.cpp dialogs/codetexthighlighter.cpp dialogs/codeviewerdialog.cpp dialogs/diagramselectiondialog.cpp dialogs/dialog_utils.cpp dialogs/dontaskagain.cpp dialogs/exportallviewsdialog.cpp dialogs/finddialog.cpp dialogs/messagewidgetpropertiesdialog.cpp dialogs/multipagedialogbase.cpp dialogs/notedialog.cpp dialogs/objectnodedialog.cpp dialogs/overwritedialog.cpp dialogs/parameterpropertiesdialog.cpp dialogs/selectoperationdialog.cpp dialogs/settingsdialog.cpp dialogs/singlepagedialogbase.cpp dialogs/statedialog.cpp dialogs/umlattributedialog.cpp dialogs/umlinstanceattributedialog.cpp dialogs/umlcheckconstraintdialog.cpp dialogs/umlentityattributedialog.cpp dialogs/umlenumliteraldialog.cpp dialogs/umlfiledialog.cpp dialogs/umlforeignkeyconstraintdialog.cpp dialogs/umloperationdialog.cpp dialogs/umlroledialog.cpp dialogs/umltemplatedialog.cpp dialogs/umluniqueconstraintdialog.cpp dialogs/umlviewdialog.cpp dialogs/pages/activitypage.cpp dialogs/pages/notepage.cpp dialogs/pages/associationgeneralpage.cpp dialogs/pages/associationrolepage.cpp dialogs/pages/autolayoutoptionpage.cpp dialogs/pages/classassociationspage.cpp dialogs/pages/classgeneralpage.cpp dialogs/pages/classifierlistpage.cpp dialogs/pages/classoptionspage.cpp dialogs/pages/codegenerationpolicypage.cpp dialogs/pages/codeimportoptionspage.cpp dialogs/pages/codevieweroptionspage.cpp dialogs/pages/constraintlistpage.cpp dialogs/pages/defaultcodegenpolicypage.cpp dialogs/pages/diagramprintpage.cpp dialogs/pages/diagrampropertiespage.cpp dialogs/pages/dialogpagebase.cpp dialogs/pages/generaloptionpage.cpp dialogs/pages/packagecontentspage.cpp dialogs/pages/selectoperationpage.cpp dialogs/pages/uioptionspage.cpp dialogs/pages/umlroleproperties.cpp dialogs/pages/umlwidgetstylepage.cpp dialogs/widgets/documentationwidget.cpp dialogs/widgets/imagetypewidget.cpp dialogs/widgets/resolutionwidget.cpp dialogs/widgets/umlartifacttypewidget.cpp dialogs/widgets/umldatatypewidget.cpp dialogs/widgets/defaultvaluewidget.cpp dialogs/widgets/umlobjectnamewidget.cpp dialogs/widgets/umlpackagewidget.cpp dialogs/widgets/umlstereotypewidget.cpp dialogs/widgets/visibilityenumwidget.cpp ) ki18n_wrap_ui( libdialogs_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/codeviewerdialogbase.ui ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/codevieweroptionsbase.ui ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/exportallviewsdialogbase.ui ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/finddialog.ui ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/pages/autolayoutoptionpage.ui ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/pages/codeimportoptionspage.ui ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/pages/diagrampropertiespage.ui ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/pages/umlrolepropertiesbase.ui ${CMAKE_CURRENT_SOURCE_DIR}/dialogs/umlinstanceattributedialog.ui ) set(librefactoring_SRCS refactoring/refactoringassistant.cpp ) set(libcodegenwizard_SRCS codegenwizard/codegenerationwizard.cpp codegenwizard/codegenoptionspage.cpp codegenwizard/codegenselectpage.cpp codegenwizard/codegenstatuspage.cpp ) ki18n_wrap_ui( libcodegenwizard_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/codegenwizard/codegenoptionspage.ui ${CMAKE_CURRENT_SOURCE_DIR}/codegenwizard/codegenselectpage.ui ${CMAKE_CURRENT_SOURCE_DIR}/codegenwizard/codegenstatuspage.ui ) set(libcodeimpwizard_SRCS codeimpwizard/codeimportingwizard.cpp codeimpwizard/codeimpselectpage.cpp codeimpwizard/codeimpstatuspage.cpp codeimpwizard/codeimpthread.cpp ) ki18n_wrap_ui( libcodeimpwizard_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/codeimpwizard/codeimpselectpage.ui ${CMAKE_CURRENT_SOURCE_DIR}/codeimpwizard/codeimpstatuspage.ui ) set(libcodeimport_SRCS codeimport/adaimport.cpp codeimport/classimport.cpp codeimport/idlimport.cpp codeimport/import_utils.cpp codeimport/javaimport.cpp codeimport/nativeimportbase.cpp codeimport/pascalimport.cpp codeimport/pythonimport.cpp codeimport/sqlimport.cpp codeimport/csharp/csharpimport.cpp ) if(BUILD_PHP_IMPORT) list(APPEND libcodeimport_SRCS codeimport/phpimport.cpp ) endif() list(APPEND libcodeimport_SRCS codeimport/cppimport.cpp ) set(libkdevcppparser_SRCS ${CMAKE_SOURCE_DIR}/lib/cppparser/ast.cpp ${CMAKE_SOURCE_DIR}/lib/cppparser/ast_utils.cpp ${CMAKE_SOURCE_DIR}/lib/cppparser/cachemanager.cpp ${CMAKE_SOURCE_DIR}/lib/cppparser/driver.cpp ${CMAKE_SOURCE_DIR}/lib/cppparser/errors.cpp ${CMAKE_SOURCE_DIR}/lib/cppparser/lexer.cpp ${CMAKE_SOURCE_DIR}/lib/cppparser/lexercache.cpp ${CMAKE_SOURCE_DIR}/lib/cppparser/lookup.cpp ${CMAKE_SOURCE_DIR}/lib/cppparser/parser.cpp ${CMAKE_SOURCE_DIR}/lib/cppparser/tree_parser.cpp ${CMAKE_SOURCE_DIR}/lib/interfaces/hashedstring.cpp codeimport/kdevcppparser/cpptree2uml.cpp ) set(libclipboard_SRCS clipboard/idchangelog.cpp clipboard/umlclipboard.cpp clipboard/umldragdata.cpp ) set(libcmds_SRCS cmds/cmdbaseobjectcommand.cpp cmds/cmdcreatediagram.cpp cmds/cmdhandlerename.cpp cmds/cmdremovediagram.cpp cmds/cmdsetstereotype.cpp cmds/cmdsetvisibility.cpp cmds/generic/cmdrenameumlinstancetype.cpp cmds/generic/cmdcreateumlobject.cpp cmds/generic/cmdremoveumlobject.cpp cmds/generic/cmdrenameumlobject.cpp cmds/widget/cmdbasewidgetcommand.cpp cmds/widget/cmdchangefont.cpp cmds/widget/cmdchangetextcolor.cpp cmds/widget/cmdchangelinecolor.cpp cmds/widget/cmdchangelinewidth.cpp cmds/widget/cmdchangefillcolor.cpp cmds/widget/cmdchangeusefillcolor.cpp cmds/widget/cmdchangemultiplicity.cpp cmds/widget/cmdchangevisualproperty.cpp cmds/widget/cmdcreatewidget.cpp cmds/widget/cmdmovewidget.cpp cmds/widget/cmdresizewidget.cpp cmds/widget/cmdremovewidget.cpp cmds/widget/cmdsetname.cpp cmds/widget/cmdsettxt.cpp ) set(libmenus_SRCS menus/listpopupmenu.cpp menus/umllistviewpopupmenu.cpp menus/umlscenepopupmenu.cpp menus/associationwidgetpopupmenu.cpp menus/widgetbasepopupmenu.cpp menus/dialogspopupmenu.cpp ) set(libumlwidgets_SRCS umlwidgets/activitywidget.cpp umlwidgets/actorwidget.cpp umlwidgets/artifactwidget.cpp umlwidgets/associationline.cpp umlwidgets/associationwidget.cpp umlwidgets/boxwidget.cpp umlwidgets/categorywidget.cpp umlwidgets/childwidgetplacement.cpp umlwidgets/childwidgetplacementpin.cpp umlwidgets/childwidgetplacementport.cpp umlwidgets/classifierwidget.cpp umlwidgets/combinedfragmentwidget.cpp umlwidgets/componentwidget.cpp umlwidgets/datatypewidget.cpp umlwidgets/entitywidget.cpp umlwidgets/enumwidget.cpp umlwidgets/floatingdashlinewidget.cpp umlwidgets/floatingtextwidget.cpp umlwidgets/forkjoinwidget.cpp + umlwidgets/interfacewidget.cpp umlwidgets/layoutgrid.cpp umlwidgets/linkwidget.cpp umlwidgets/messagewidget.cpp umlwidgets/nodewidget.cpp umlwidgets/notewidget.cpp umlwidgets/objectnodewidget.cpp umlwidgets/objectwidget.cpp umlwidgets/packagewidget.cpp umlwidgets/pinportbase.cpp umlwidgets/pinwidget.cpp umlwidgets/portwidget.cpp umlwidgets/preconditionwidget.cpp umlwidgets/regionwidget.cpp umlwidgets/seqlinewidget.cpp umlwidgets/signalwidget.cpp umlwidgets/statewidget.cpp umlwidgets/toolbarstateonewidget.cpp umlwidgets/umlwidget.cpp umlwidgets/usecasewidget.cpp umlwidgets/widget_factory.cpp umlwidgets/widget_utils.cpp umlwidgets/widgetbase.cpp umlwidgets/widgetlist_utils.cpp umlwidgets/statusbartoolbutton.cpp ) set(libfinder_SRCS finder/findresults.cpp finder/umldocfinder.cpp finder/umlfinder.cpp finder/umllistviewfinder.cpp finder/umlscenefinder.cpp ) set(libuml_SRCS uml1model/actor.cpp uml1model/artifact.cpp uml1model/association.cpp uml1model/attribute.cpp uml1model/category.cpp uml1model/checkconstraint.cpp uml1model/classifier.cpp uml1model/classifierlistitem.cpp uml1model/component.cpp uml1model/datatype.cpp uml1model/entity.cpp uml1model/entityattribute.cpp uml1model/entityconstraint.cpp uml1model/enum.cpp uml1model/enumliteral.cpp uml1model/folder.cpp uml1model/foreignkeyconstraint.cpp uml1model/node.cpp uml1model/operation.cpp uml1model/package.cpp uml1model/port.cpp uml1model/stereotype.cpp uml1model/template.cpp uml1model/umlattributelist.cpp uml1model/umlcanvasobject.cpp uml1model/umlclassifierlistitemlist.cpp uml1model/umlentityattributelist.cpp uml1model/umlentityconstraintlist.cpp uml1model/umlobject.cpp uml1model/umlobjectlist.cpp uml1model/umlrole.cpp uml1model/usecase.cpp uml1model/uniqueconstraint.cpp uml1model/instance.cpp uml1model/instanceattribute.cpp ) set(umbrellobase_SRCS assocrules.cpp basictypes.cpp birdview.cpp codeviewerstate.cpp cmdlineexportallviewsevent.cpp diagramswindow.cpp diagram_utils.cpp objectswindow.cpp docwindow.cpp dotgenerator.cpp icon_utils.cpp import_argo.cpp import_rose.cpp layoutgenerator.cpp model_utils.cpp object_factory.cpp optionstate.cpp petalnode.cpp petaltree2uml.cpp stereotypeswindow.cpp toolbarstatearrow.cpp toolbarstateassociation.cpp toolbarstate.cpp toolbarstatefactory.cpp toolbarstatemessages.cpp toolbarstateother.cpp toolbarstatepool.cpp umlappprivate.cpp uml.cpp umldoc.cpp umllistview.cpp umllistviewitem.cpp umlscene.cpp umlview.cpp umlviewimageexporterall.cpp umlviewimageexporter.cpp umlviewimageexportermodel.cpp uniqueid.cpp worktoolbar.cpp ) set(umbrellomodels_SRCS models/diagramsmodel.cpp models/objectsmodel.cpp models/stereotypesmodel.cpp ) kconfig_add_kcfg_files(umbrellobase_SRCS umbrellosettings.kcfgc) set(libumbrello_SRCS ${libdebug_SRCS} ${libdialogs_SRCS} ${libfinder_SRCS} ${librefactoring_SRCS} ${libcodegenwizard_SRCS} ${libcodeimpwizard_SRCS} ${libclassparser_SRCS} ${libclipboard_SRCS} ${libkdevcppparser_SRCS} ${libcodeimport_SRCS} ${libcodegenerator_SRCS} ${libdocgenerator_SRCS} ${libcmds_SRCS} ${libmenus_SRCS} ${libuml_SRCS} ${libumlwidgets_SRCS} ${umbrellobase_SRCS} ${umbrellomodels_SRCS} ) set(umbrello_SRCS main.cpp ) set(LIB_BUILD_MODE STATIC) if(NOT BUILD_KF5) if(CMAKE_MAJOR_VERSION LESS 3) qt4_add_resources(libumbrello_SRCS icons.qrc) else() list(APPEND libumbrello_SRCS icons.qrc) endif() kde4_add_library(libumbrello ${LIB_BUILD_MODE} ${libumbrello_SRCS}) set_target_properties(libumbrello PROPERTIES OUTPUT_NAME umbrello) target_link_libraries(libumbrello Qt4::QtCore Qt4::QtGui Qt4::QtXml Qt4::QtWebKit ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${KDE4_KTEXTEDITOR_LIBS} ${KDE4_KFILE_LIBS} ) if(BUILD_PHP_IMPORT) target_link_libraries(libumbrello ${KDEVPLATFORM_INTERFACES_LIBRARIES} ${KDEVPLATFORM_LANGUAGE_LIBRARIES} ${KDEVPLATFORM_OUTPUTVIEW_LIBRARIES} ${KDEVPLATFORM_PROJECT_LIBRARIES} ${KDEVPLATFORM_SUBLIME_LIBRARIES} ${KDEVPLATFORM_SHELL_LIBRARIES} ${KDEVPLATFORM_UTIL_LIBRARIES} ${KDEVPLATFORM_VCS_LIBRARIES} ${KDEVPLATFORM_DEBUGGER_LIBRARIES} ${KDEVPLATFORM_DOCUMENTATION_LIBRARIES} ${KDEVPLATFORM_TESTS_LIBRARIES} ${KDEVPLATFORM_JSONTESTS_LIBRARIES} kdev4phpparser ) endif() kde4_add_app_icon(umbrello_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/pics/global/kde4/hi*-apps-umbrello.png") kde4_add_executable(umbrello ${umbrello_SRCS}) target_link_libraries(umbrello ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${KDE4_KTEXTEDITOR_LIBS} ${KDE4_KFILE_LIBS} libumbrello) else() if(CMAKE_MAJOR_VERSION LESS 3) qt5_add_resources(libumbrello_SRCS icons.qrc ${CMAKE_CURRENT_BINARY_DIR}/ui.qrc) else() list(APPEND libumbrello_SRCS icons.qrc ${CMAKE_CURRENT_BINARY_DIR}/ui.qrc) endif() add_library(libumbrello ${LIB_BUILD_MODE} ${libumbrello_SRCS}) set_target_properties(libumbrello PROPERTIES OUTPUT_NAME umbrello) target_link_libraries(libumbrello Qt5::Widgets Qt5::Xml Qt5::PrintSupport Qt5::Svg Qt5::WebKitWidgets KF5::Archive KF5::Completion KF5::CoreAddons KF5::I18n KF5::IconThemes KF5::KIOCore KF5::KDELibs4Support KF5::TextEditor KF5::WidgetsAddons KF5::XmlGui KF5::Crash ${LIBXSLT_LIBRARIES} ${LIBXML2_LIBRARIES} ) if(BUILD_PHP_IMPORT) target_link_libraries(libumbrello KDev::Interfaces KDev::Language KDev::Tests kdevphpparser ) endif() ecm_add_app_icon(umbrello_SRCS ICONS ${CMAKE_CURRENT_SOURCE_DIR}/pics/global/16-apps-umbrello.png ${CMAKE_CURRENT_SOURCE_DIR}/pics/global/22-apps-umbrello.png ${CMAKE_CURRENT_SOURCE_DIR}/pics/global/32-apps-umbrello.png ${CMAKE_CURRENT_SOURCE_DIR}/pics/global/48-apps-umbrello.png ${CMAKE_CURRENT_SOURCE_DIR}/pics/global/64-apps-umbrello.png ${CMAKE_CURRENT_SOURCE_DIR}/pics/global/128-apps-umbrello.png ) add_executable(umbrello ${umbrello_SRCS}) target_link_libraries(umbrello libumbrello KF5::Crash KF5::WindowSystem KF5::KDELibs4Support ) set_target_properties(umbrello PROPERTIES OUTPUT_NAME umbrello5) endif() if(LIB_BUILD_MODE EQUAL SHARED) install(TARGETS libumbrello ${INSTALL_TARGETS_DEFAULT_ARGS} ) endif() install(TARGETS umbrello ${INSTALL_TARGETS_DEFAULT_ARGS} ) ########### install files ############# if(NOT BUILD_KF5) install( PROGRAMS org.kde.umbrello.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/umbrelloui.rc DESTINATION ${UMBRELLO_DATA_INSTALL_DIR} ) else() file(READ org.kde.umbrello.desktop UMBRELLO_DESKTOP_OUT) string(REPLACE "Exec=umbrello" "Exec=umbrello5" UMBRELLO_DESKTOP_OUT "${UMBRELLO_DESKTOP_OUT}") file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/org.kde.umbrello.desktop "${UMBRELLO_DESKTOP_OUT}") install( PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/org.kde.umbrello.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) install(FILES org.kde.umbrello.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) endif() install( FILES docgenerators/xmi2docbook.xsl docgenerators/docbook2xhtml.xsl docgenerators/xmi.css docgenerators/common.ent DESTINATION ${UMBRELLO_DATA_INSTALL_DIR} ) install( DIRECTORY layouts DESTINATION ${UMBRELLO_DATA_INSTALL_DIR} PATTERN .svn EXCLUDE ) add_subdirectory( pics ) diff --git a/umbrello/codeimport/kdevcppparser/cpptree2uml.cpp b/umbrello/codeimport/kdevcppparser/cpptree2uml.cpp index e523ea180..3bc6522c2 100644 --- a/umbrello/codeimport/kdevcppparser/cpptree2uml.cpp +++ b/umbrello/codeimport/kdevcppparser/cpptree2uml.cpp @@ -1,815 +1,819 @@ /*************************************************************************** * Based on kdevelop-3.0 languages/cpp/store_walker.cpp by Roberto Raggi * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * copyright (C) 2004-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "cpptree2uml.h" // app includes #include "uml.h" #include "umldoc.h" #include "umllistview.h" #include "datatype.h" #include "operation.h" #include "debug_utils.h" #include "ast_utils.h" #include "codeimpthread.h" #include "driver.h" #include "import_utils.h" // FIXME: The sole reason for the next 2 includes is parseTypedef(). // Make capsule methods in ClassImport, and remove these includes. #include "classifier.h" // FIXME The next include is motivated by template params #include "template.h" // qt includes #include #include #include #include CppTree2Uml::CppTree2Uml(const QString& fileName, CodeImpThread* thread) : m_thread(thread), m_rootFolder(0), m_doc(UMLApp::app()->document()) { clear(); QDir dir(fileName); m_fileName = dir.canonicalPath(); } CppTree2Uml::~CppTree2Uml() { } void CppTree2Uml::clear() { m_currentScope.clear(); m_currentNamespace[0] = 0; // index 0 is reserved (always 0) m_currentClass[0] = 0; // index 0 is reserved (always 0) m_nsCnt = 0; m_clsCnt = 0; m_currentAccess = Uml::Visibility::Public; m_inSlots = false; m_inSignals = false; m_inStorageSpec = false; m_inTypedef = false; m_currentDeclarator = 0; m_anon = 0; } void CppTree2Uml::setRootPath(const QString &rootPath) { m_rootPath = QDir::fromNativeSeparators(rootPath); if (Settings::optionState().codeImportState.createArtifacts) { if (!m_rootFolder) { UMLFolder *componentView = m_doc->rootFolder(Uml::ModelType::Component); if (!m_rootPath.isEmpty()) { UMLFolder *root = Import_Utils::createSubDir(m_rootPath, componentView); m_rootFolder = root; } else { m_rootFolder = componentView; } } } } void CppTree2Uml::parseTranslationUnit(const ParsedFile &file) { clear(); if (Settings::optionState().codeImportState.createArtifacts) { QFileInfo fi(file.fileName()); UMLFolder *parent = m_rootFolder; - QString path = fi.path().replace(m_rootPath + QLatin1String("/"), QLatin1String("")); + QString path; + if (!m_rootPath.isEmpty()) + path = fi.path().replace(m_rootPath + QLatin1String("/"), QLatin1String("")); + else + path = fi.absolutePath(); if (!path.isEmpty()) parent = Import_Utils::createSubDir(path, m_rootFolder); Import_Utils::createArtifact(fi.fileName(), parent, file->comment()); } TreeParser::parseTranslationUnit(file); } void CppTree2Uml::parseNamespace(NamespaceAST* ast) { if (m_clsCnt > 0) { uDebug() << "error - cannot nest namespace inside class"; return; } QString nsName; if (!ast->namespaceName() || ast->namespaceName()->text().isEmpty()){ QFileInfo fileInfo(m_fileName); QString shortFileName = fileInfo.baseName(); nsName.sprintf("(%s_%d)", shortFileName.toLocal8Bit().constData(), m_anon++); } else { nsName = ast->namespaceName()->text(); } uDebug() << nsName; if (m_thread) { m_thread->emitMessageToLog(QString(), QLatin1String("namespace ") + nsName); } UMLObject *o = m_doc->findUMLObject(nsName, UMLObject::ot_Package, m_currentNamespace[m_nsCnt]); if (!o) o = m_doc->findUMLObject(nsName, UMLObject::ot_Class, m_currentNamespace[m_nsCnt]); if (o && o->stereotype() == QLatin1String("class-or-package")) { o->setStereotype(QString()); o->setBaseType(UMLObject::ot_Package); } // TODO reduce multiple finds else o = Import_Utils::createUMLObject(UMLObject::ot_Package, nsName, m_currentNamespace[m_nsCnt], ast->comment()); UMLPackage *ns = (UMLPackage *)o; m_currentScope.push_back(nsName); if (++m_nsCnt > STACKSIZE) { uError() << "excessive namespace nesting"; m_nsCnt = STACKSIZE; } m_currentNamespace[m_nsCnt] = ns; TreeParser::parseNamespace(ast); --m_nsCnt; m_currentScope.pop_back(); } void CppTree2Uml::parseTypedef(TypedefAST* ast) { TypeSpecifierAST* typeSpec = ast->typeSpec(); InitDeclaratorListAST* declarators = ast->initDeclaratorList(); if (typeSpec && declarators){ QString typeId; if (typeSpec->name()) typeId = typeSpec->name()->text(); QList l(declarators->initDeclaratorList()); InitDeclaratorAST* initDecl = 0; for (int i = 0; i < l.size(); ++i) { initDecl = l.at(i); if (initDecl==0) break; QString type, id; if (initDecl->declarator()){ type = typeOfDeclaration(typeSpec, initDecl->declarator()); DeclaratorAST* d = initDecl->declarator(); while (d->subDeclarator()){ d = d->subDeclarator(); } if (d->declaratorId()) id = d->declaratorId()->text(); } /* @todo Trace typedefs back to their root type for deciding whether to build a Datatype (for pointers.) */ /* check out if the ID type is a Datatype ex: typedef unsigned int uint; where unsigned int is a known datatype I'm not sure if setIsReference() should be run */ bool isDatatype = Import_Utils::isDatatype(typeId, m_currentNamespace[m_nsCnt]); if (type.contains(QLatin1Char('*')) || isDatatype) { UMLObject *inner = 0; if (m_currentNamespace[m_nsCnt] && m_currentNamespace[m_nsCnt]->baseType() == UMLObject::ot_Class && typeId == m_currentNamespace[m_nsCnt]->name()) inner = m_currentNamespace[m_nsCnt]; else inner = Import_Utils::createUMLObject(UMLObject::ot_Class, type, m_currentNamespace[m_nsCnt]); UMLObject *typedefObj = Import_Utils::createUMLObject(UMLObject::ot_Datatype, id, m_currentNamespace[m_nsCnt]); UMLDatatype *dt = typedefObj->asUMLDatatype(); if (dt) { dt->setIsReference(); dt->setOriginType(inner->asUMLClassifier()); } else { uError() << "Could not create datatype from" << id; } } else { Import_Utils::createUMLObject(UMLObject::ot_Class, id, m_currentNamespace[m_nsCnt], QString() /* doc */, QLatin1String("typedef") /* stereotype */); } } } } void CppTree2Uml::parseTemplateDeclaration(TemplateDeclarationAST* ast) { TemplateParameterListAST* parmListAST = ast->templateParameterList(); if (parmListAST == 0) return; QList parmList = parmListAST->templateParameterList(); for (int i = 0; i < parmList.size(); ++i) { // The template is either a typeParameter or a typeValueParameter. TemplateParameterAST* tmplParmNode = parmList.at(i); TypeParameterAST* typeParmNode = tmplParmNode->typeParameter(); if (typeParmNode) { NameAST* nameNode = typeParmNode->name(); if (nameNode) { QString typeName = nameNode->unqualifiedName()->text(); Model_Utils::NameAndType nt(typeName, 0); m_templateParams.append(nt); } else { uError() << "nameNode is NULL"; } } ParameterDeclarationAST* valueNode = tmplParmNode->typeValueParameter(); if (valueNode) { TypeSpecifierAST* typeSpec = valueNode->typeSpec(); if (typeSpec == 0) { uError() << "typeSpec is NULL"; continue; } QString typeName = typeSpec->name()->text(); UMLObject *t = Import_Utils::createUMLObject(UMLObject::ot_UMLObject, typeName, m_currentNamespace[m_nsCnt]); DeclaratorAST* declNode = valueNode->declarator(); NameAST* nameNode = declNode->declaratorId(); if (nameNode == 0) { uError() << "CppTree2Uml::parseTemplateDeclaration(value):" << " nameNode is NULL"; continue; } QString paramName = nameNode->unqualifiedName()->text(); Model_Utils::NameAndType nt(paramName, t); m_templateParams.append(nt); } } if (ast->declaration()) TreeParser::parseDeclaration(ast->declaration()); } void CppTree2Uml::parseSimpleDeclaration(SimpleDeclarationAST* ast) { TypeSpecifierAST* typeSpec = ast->typeSpec(); InitDeclaratorListAST* declarators = ast->initDeclaratorList(); GroupAST* storageSpec = ast->storageSpecifier(); if (storageSpec && storageSpec->text() == QLatin1String("friend")) return; m_comment = ast->comment(); if (typeSpec) parseTypeSpecifier(typeSpec); if (declarators){ QList l = declarators->initDeclaratorList(); for (int i = 0; i < l.size(); ++i) { parseDeclaration2(ast->functionSpecifier(), ast->storageSpecifier(), typeSpec, l.at(i)); } } } void CppTree2Uml::parseFunctionDefinition(FunctionDefinitionAST* ast) { TypeSpecifierAST* typeSpec = ast->typeSpec(); GroupAST* funSpec = ast->functionSpecifier(); GroupAST* storageSpec = ast->storageSpecifier(); if (!ast->initDeclarator()) return; DeclaratorAST* d = ast->initDeclarator()->declarator(); if (!d->declaratorId()) return; bool isFriend = false; bool isVirtual = false; bool isStatic = false; bool isInline = false; bool isConstructor = false; bool isDestructor = false; bool isExplicit = false; bool isConstExpression = false; if (funSpec){ QList l = funSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("virtual")) isVirtual = true; else if (text == QLatin1String("inline")) isInline = true; else if (text == QLatin1String("explicit")) isExplicit = true; } } if (storageSpec){ QList l = storageSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("friend")) isFriend = true; else if (text == QLatin1String("static")) isStatic = true; else if (text == QLatin1String("constexpr")) isConstExpression = true; } } QString id = d->declaratorId()->unqualifiedName()->text().trimmed(); if (m_thread) { m_thread->emitMessageToLog(QString(), QLatin1String("method ") + id); } uDebug() << id; UMLClassifier *c = m_currentClass[m_clsCnt]; if (c == 0) { uDebug() << id << ": need a surrounding class."; return; } QString returnType = typeOfDeclaration(typeSpec, d); UMLOperation *m = Import_Utils::makeOperation(c, id); if (isConstExpression) m->setStereotype(QLatin1String("constexpr")); if (isVirtual) m->setVirtual(true); if (isInline) m->setInline(true); if (d->override()) m->setOverride(true); if (d->constant()) m->setConst(true); // if a class has no return type, it could be a constructor or // a destructor if (d && returnType.isEmpty()) { if (id.indexOf(QLatin1Char('~')) == -1) isConstructor = true; else isDestructor = true; } parseFunctionArguments(d, m); Import_Utils::insertMethod(c, m, m_currentAccess, returnType, isStatic, false /*isAbstract*/, isFriend, isConstructor, isDestructor, m_comment); m_comment = QString(); if (isConstructor) { QString stereotype; if (isExplicit) stereotype.append(QLatin1String("explicit ")); if (isConstExpression) stereotype.append(QLatin1String("constexpr ")); stereotype.append(QLatin1String("constructor")); m->setStereotype(stereotype); } else if (isConstExpression) m->setStereotype(QLatin1String("constexpr")); /* For reference, Kdevelop does some more: method->setFileName(m_fileName); if (m_inSignals) method->setSignal(true); if (m_inSlots) method->setSlot(true); */ } void CppTree2Uml::parseClassSpecifier(ClassSpecifierAST* ast) { Uml::Visibility::Enum oldAccess = m_currentAccess; bool oldInSlots = m_inSlots; bool oldInSignals = m_inSignals; QString kind = ast->classKey()->text(); m_currentAccess = Uml::Visibility::fromString(kind); m_inSlots = false; m_inSignals = false; QString className; if (!ast->name() && m_currentDeclarator && m_currentDeclarator->declaratorId()) { className = m_currentDeclarator->declaratorId()->text().trimmed(); } else if (!ast->name()){ QFileInfo fileInfo(m_fileName); QString shortFileName = fileInfo.baseName(); className.sprintf("(%s_%d)", shortFileName.toLocal8Bit().constData(), m_anon++); } else { className = ast->name()->unqualifiedName()->text().trimmed(); } uDebug() << "name=" << className; if (m_thread) { m_thread->emitMessageToLog(QString(), QLatin1String("class ") + className); } QStringList scope = scopeOfName(ast->name(), QStringList()); UMLObject *localParent = 0; if (!scope.isEmpty()) { localParent = m_doc->findUMLObject(scope.join(QLatin1String("::")), UMLObject::ot_Class, m_currentNamespace[m_nsCnt]); if (!localParent) localParent = m_doc->findUMLObject(scope.join(QLatin1String("::")), UMLObject::ot_Package, m_currentNamespace[m_nsCnt]); if (!localParent) { localParent = Import_Utils::createUMLObject(UMLObject::ot_Class, className, m_currentNamespace[m_nsCnt], ast->comment(), QString(), true); localParent->setStereotype(QLatin1String("class-or-package")); } m_currentNamespace[++m_nsCnt] = localParent->asUMLPackage(); } if (className.isEmpty()) { className = QLatin1String("anon_") + QString::number(m_anon); m_anon++; } UMLObject *o = m_doc->findUMLObject(className, UMLObject::ot_Class, m_currentNamespace[m_nsCnt]); if (!o) o = m_doc->findUMLObject(className, UMLObject::ot_Datatype, m_currentNamespace[m_nsCnt]); if (o && o->stereotype() == QLatin1String("class-or-package")) { o->setStereotype(QString()); o->setBaseType(UMLObject::ot_Class); } // TODO reduce multiple finds else o = Import_Utils::createUMLObject(UMLObject::ot_Class, className, m_currentNamespace[m_nsCnt], ast->comment(), QString(), true); UMLClassifier *klass = o->asUMLClassifier(); flushTemplateParams(klass); if (ast->baseClause()) parseBaseClause(ast->baseClause(), klass); m_currentScope.push_back(className); if (++m_clsCnt > STACKSIZE) { uError() << "excessive class nesting"; m_clsCnt = STACKSIZE; } m_currentClass[m_clsCnt] = klass; if (++m_nsCnt > STACKSIZE) { uError() << "excessive namespace nesting"; m_nsCnt = STACKSIZE; } m_currentNamespace[m_nsCnt] = (UMLPackage*)klass; TreeParser::parseClassSpecifier(ast); --m_nsCnt; --m_clsCnt; m_currentScope.pop_back(); // check is class is an interface bool isInterface = true; foreach(UMLOperation *op, klass->getOpList()) { if (!op->isDestructorOperation() && op->isAbstract() == false) isInterface = false; } foreach(UMLAttribute *attr, klass->getAttributeList()) { if (!(attr->isStatic() && attr->getTypeName().contains(QLatin1String("const")))) isInterface = false; } if (isInterface) klass->setBaseType(UMLObject::ot_Interface); m_currentAccess = oldAccess; m_inSlots = oldInSlots; m_inSignals = oldInSignals; if (localParent) m_currentNamespace[m_nsCnt--] = 0; } void CppTree2Uml::parseEnumSpecifier(EnumSpecifierAST* ast) { NameAST *nameNode = ast->name(); if (nameNode == 0) return; // skip constants QString typeName = nameNode->unqualifiedName()->text().trimmed(); if (typeName.isEmpty()) return; // skip constants UMLObject *o = Import_Utils::createUMLObject(UMLObject::ot_Enum, typeName, m_currentNamespace[m_nsCnt], ast->comment()); QList l = ast->enumeratorList(); for (int i = 0; i < l.size(); ++i) { QString enumLiteral = l.at(i)->id()->text(); QString enumLiteralValue = QString(); if (l.at(i)->expr()) { enumLiteralValue = l.at(i)->expr()->text(); } Import_Utils::addEnumLiteral((UMLEnum*)o, enumLiteral, QString(), enumLiteralValue); } } void CppTree2Uml::parseElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST* typeSpec) { // This is invoked for forward declarations. /// @todo Refine - Currently only handles class forward declarations. /// - Using typeSpec->text() is probably not good, decode /// the kind() instead. QString text = typeSpec->text(); uDebug() << "forward declaration of " << text; if (m_thread) { m_thread->emitMessageToLog(QString(), QLatin1String("forward declaration of ") + text); } text.remove(QRegExp(QLatin1String("^class\\s+"))); #if 0 if (m_thread) { //:TODO: for testing only int answer; m_thread->emitAskQuestion("Soll CppTree2Uml::parseElaboratedTypeSpecifier ausgeführt werden?"); uDebug() << "Antwort: " << answer; } #endif UMLObject *o = Import_Utils::createUMLObject(UMLObject::ot_Class, text, m_currentNamespace[m_nsCnt]); #if 0 if (m_thread) { //:TODO: for testing only m_thread->emitAskQuestion("Soll nach CppTree2Uml::parseElaboratedTypeSpecifier weiter gemacht werden?"); } #endif flushTemplateParams(o->asUMLClassifier()); } void CppTree2Uml::parseDeclaration2(GroupAST* funSpec, GroupAST* storageSpec, TypeSpecifierAST* typeSpec, InitDeclaratorAST* decl) { if (m_inStorageSpec) return; DeclaratorAST* d = decl->declarator(); if (!d) return; if (!d->subDeclarator() && d->parameterDeclarationClause()) return parseFunctionDeclaration(funSpec, storageSpec, typeSpec, decl); DeclaratorAST* t = d; while (t && t->subDeclarator()) t = t->subDeclarator(); QString id; if (t && t->declaratorId() && t->declaratorId()->unqualifiedName()) id = t->declaratorId()->unqualifiedName()->text(); if (!scopeOfDeclarator(d, QStringList()).isEmpty()){ uDebug() << id << ": skipping."; return; } UMLClassifier *c = m_currentClass[m_clsCnt]; if (c == 0) { uDebug() << id << ": need a surrounding class."; return; } QString typeName = typeOfDeclaration(typeSpec, d); bool isFriend = false; bool isStatic = false; //:unused: bool isInitialized = decl->initializer() != 0; if (storageSpec){ QList l = storageSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("static")) isStatic = true; else if (text == QLatin1String("mutable")) typeName.prepend(text + QLatin1String(" ")); else if (text == QLatin1String("friend")) isFriend = true; } } UMLAttribute *attribute = Import_Utils::insertAttribute(c, m_currentAccess, id, typeName, m_comment, isStatic); if (isFriend) attribute->setStereotype(QLatin1String("friend")); m_comment = QString(); } void CppTree2Uml::parseAccessDeclaration(AccessDeclarationAST * access) { QList l = access->accessList(); QString accessStr = l.at(0)->text(); m_currentAccess=Uml::Visibility::fromString(accessStr); m_inSlots = l.count() > 1 ? l.at(1)->text() == QLatin1String("slots") : false; m_inSignals = l.count() >= 1 ? l.at(0)->text() == QLatin1String("signals") : false; } void CppTree2Uml::parseFunctionDeclaration(GroupAST* funSpec, GroupAST* storageSpec, TypeSpecifierAST * typeSpec, InitDeclaratorAST * decl) { bool isFriend = false; bool isVirtual = false; bool isStatic = false; bool isInline = false; bool isPure = decl->initializer() != 0; bool isConstructor = false; bool isConstExpression = false; bool isDestructor = false; bool isExplicit = false; if (funSpec){ QList l = funSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("virtual")) isVirtual = true; else if (text == QLatin1String("inline")) isInline = true; else if (text == QLatin1String("explicit")) isExplicit = true; } } if (storageSpec){ QList l = storageSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("friend")) isFriend = true; else if (text == QLatin1String("static")) isStatic = true; else if (text == QLatin1String("constexpr")) isConstExpression = true; } } DeclaratorAST* d = decl->declarator(); QString id = d->declaratorId()->unqualifiedName()->text(); UMLClassifier *c = m_currentClass[m_clsCnt]; if (c == 0) { uDebug() << id << ": need a surrounding class."; return; } QString returnType = typeOfDeclaration(typeSpec, d); UMLOperation *m = Import_Utils::makeOperation(c, id); if (d->override()) m->setOverride(true); if (d->constant()) m->setConst(true); if (isConstExpression) m->setStereotype(QLatin1String("constexpr")); if (isVirtual) m->setVirtual(true); if (isInline) m->setInline(true); // if a class has no return type, it could de a constructor or // a destructor if (d && returnType.isEmpty()) { if (id.indexOf(QLatin1Char('~')) == -1) isConstructor = true; else isDestructor = true; } parseFunctionArguments(d, m); Import_Utils::insertMethod(c, m, m_currentAccess, returnType, isStatic, isPure, isFriend, isConstructor, isDestructor, m_comment); if (isPure) c->setAbstract(true); if (isConstructor) { QString stereotype; if (isExplicit) stereotype.append(QLatin1String("explicit ")); if (isConstExpression) stereotype.append(QLatin1String("constexpr ")); stereotype.append(QLatin1String("constructor")); m->setStereotype(stereotype); } else if (isConstExpression) m->setStereotype(QLatin1String("constexpr")); m_comment = QString(); } void CppTree2Uml::parseFunctionArguments(DeclaratorAST* declarator, UMLOperation* method) { if (!declarator) return; ParameterDeclarationClauseAST* clause = declarator->parameterDeclarationClause(); if (clause && clause->parameterDeclarationList()){ ParameterDeclarationListAST* params = clause->parameterDeclarationList(); QList l(params->parameterList()); for (int i = 0; i < l.size(); ++i) { ParameterDeclarationAST* param = l.at(i); QString name; if (param->declarator()) name = declaratorToString(param->declarator(), QString(), true); QString tp = typeOfDeclaration(param->typeSpec(), param->declarator()); if (tp != QLatin1String("void")) Import_Utils::addMethodParameter(method, tp, name); } } } QString CppTree2Uml::typeOfDeclaration(TypeSpecifierAST* typeSpec, DeclaratorAST* declarator) { if (!typeSpec || !declarator) return QString(); QString text; text += typeSpec->text(); QList ptrOpList = declarator->ptrOpList(); for (int i = 0; i < ptrOpList.size(); ++i) { text += ptrOpList.at(i)->text(); } QList arrays = declarator->arrayDimensionList(); for(int i = 0; i < arrays.size(); ++i) { text += arrays.at(i)->text().replace(QLatin1String(" "), QLatin1String("")); } return text; } void CppTree2Uml::parseBaseClause(BaseClauseAST * baseClause, UMLClassifier* klass) { QList l = baseClause->baseSpecifierList(); for (int i = 0; i < l.size(); ++i) { BaseSpecifierAST* baseSpecifier = l.at(i); NameAST *name = baseSpecifier->name(); if (name == 0) { uDebug() << "baseSpecifier->name() is NULL"; continue; } ClassOrNamespaceNameAST *cons = name->unqualifiedName(); if (cons == 0) { uDebug() << "name->unqualifiedName() is NULL"; continue; } QString baseName = cons->name()->text(); Import_Utils::putAtGlobalScope(true); UMLObject *c = Import_Utils::createUMLObject(UMLObject::ot_Class, baseName, m_currentNamespace[m_nsCnt], baseSpecifier->comment()); Import_Utils::putAtGlobalScope(false); Import_Utils::createGeneralization(klass, c->asUMLClassifier()); } } QStringList CppTree2Uml::scopeOfName(NameAST* id, const QStringList& startScope) { QStringList scope = startScope; if (id && id->classOrNamespaceNameList().count()){ if (id->isGlobal()) scope.clear(); QList l = id->classOrNamespaceNameList(); for (int i = 0; i < l.size(); ++i) { if (l.at(i)->name()){ scope << l.at(i)->name()->text(); } } } return scope; } QStringList CppTree2Uml::scopeOfDeclarator(DeclaratorAST* d, const QStringList& startScope) { return scopeOfName(d->declaratorId(), startScope); } /** * Flush template parameters pending in m_templateParams to the klass. */ void CppTree2Uml::flushTemplateParams(UMLClassifier *klass) { if (m_templateParams.count()) { Model_Utils::NameAndType_ListIt it; for (it = m_templateParams.begin(); it != m_templateParams.end(); ++it) { const Model_Utils::NameAndType &nt = *it; uDebug() << "adding template param: " << nt.m_name; UMLTemplate *tmpl = klass->addTemplate(nt.m_name); tmpl->setType(nt.m_type); } m_templateParams.clear(); } } diff --git a/umbrello/menus/widgetbasepopupmenu.cpp b/umbrello/menus/widgetbasepopupmenu.cpp index bb4c147d9..361c920a0 100644 --- a/umbrello/menus/widgetbasepopupmenu.cpp +++ b/umbrello/menus/widgetbasepopupmenu.cpp @@ -1,679 +1,680 @@ /*************************************************************************** * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * copyright (C) 2018 * * Umbrello UML Modeller Authors * ***************************************************************************/ #include "widgetbasepopupmenu.h" // app includes #include "activitywidget.h" #include "category.h" #include "classifier.h" #include "combinedfragmentwidget.h" #include "debug_utils.h" #include "entitywidget.h" #include "floatingtextwidget.h" #include "forkjoinwidget.h" +#include "interfacewidget.h" #include "notewidget.h" #include "objectwidget.h" #include "objectnodewidget.h" #include "pinportbase.h" #include "statewidget.h" #include "uml.h" #include "umllistview.h" #include "umlscene.h" // kde includes #include static const bool CHECKABLE = true; /** * Constructs the popup menu for a scene widget. * * @param parent The parent to ListPopupMenu. * @param widget The WidgetBase to represent a menu for. * @param multi True if multiple items are selected. * @param uniqueType The type of widget shared by all selected widgets */ WidgetBasePopupMenu::WidgetBasePopupMenu(QWidget * parent, WidgetBase * widget, bool multi, WidgetBase::WidgetType uniqueType) : ListPopupMenu(parent) { if (!widget) return; if (multi) { insertMultiSelectionMenu(uniqueType); } else { insertSingleSelectionMenu(widget); } bool bCutState = UMLApp::app()->isCutCopyState(); setActionEnabled(mt_Cut, bCutState); setActionEnabled(mt_Copy, bCutState); bool pasteAvailable = false; if (widget->isNoteWidget() && UMLApp::app()->listView()->startedCopy()) { NoteWidget::s_pCurrentNote = widget->asNoteWidget(); pasteAvailable = true; } setActionEnabled(mt_Paste, pasteAvailable); setActionChecked(mt_AutoResize, widget->autoResize()); setupActionsData(); } /** * Creates the "Show" submenu in the context menu of one classifier widget */ void WidgetBasePopupMenu::makeClassifierShowPopup(ClassifierWidget *c) { WidgetBase::WidgetType type = c->baseType(); KMenu* show = newMenu(i18n("Show"), this); show->setIcon(Icon_Utils::SmallIcon(Icon_Utils::it_Show)); #ifdef ENABLE_WIDGET_SHOW_DOC insert(mt_Show_Documentation, show, i18n("Documentation"), CHECKABLE); setActionChecked(mt_Show_Documentation, c->visualProperty(ClassifierWidget::ShowDocumentation)); #endif if (type == WidgetBase::wt_Class) { insert(mt_Show_Attributes, show, i18n("Attributes"), CHECKABLE); setActionChecked(mt_Show_Attributes, c->visualProperty(ClassifierWidget::ShowAttributes)); } insert(mt_Show_Operations, show, i18n("Operations"), CHECKABLE); setActionChecked(mt_Show_Operations, c->visualProperty(ClassifierWidget::ShowOperations)); insert(mt_Show_Public_Only, show, i18n("Public Only"), CHECKABLE); setActionChecked(mt_Show_Public_Only, c->visualProperty(ClassifierWidget::ShowPublicOnly)); insert(mt_Visibility, show, i18n("Visibility"), CHECKABLE); setActionChecked(mt_Visibility, c->visualProperty(ClassifierWidget::ShowVisibility)); insert(mt_Show_Operation_Signature, show, i18n("Operation Signature"), CHECKABLE); bool sig = (c->operationSignature() == Uml::SignatureType::SigNoVis || c->operationSignature() == Uml::SignatureType::ShowSig); setActionChecked(mt_Show_Operation_Signature, sig); if (type == WidgetBase::wt_Class) { insert(mt_Show_Attribute_Signature, show, i18n("Attribute Signature"), CHECKABLE); sig = (c->attributeSignature() == Uml::SignatureType::SigNoVis || c->attributeSignature() == Uml::SignatureType::ShowSig); setActionChecked(mt_Show_Attribute_Signature, sig); } insert(mt_Show_Packages, show, i18n("Package"), CHECKABLE); setActionChecked(mt_Show_Packages, c->visualProperty(ClassifierWidget::ShowPackage)); insert(mt_Show_Stereotypes, show, i18n("Stereotype"), CHECKABLE); setActionChecked(mt_Show_Stereotypes, c->visualProperty(ClassifierWidget::ShowStereotype)); addMenu(show); } /** * Creates the "Show" submenu the context menu of multiple classifier widgets */ void WidgetBasePopupMenu::makeMultiClassifierShowPopup(WidgetBase::WidgetType type) { KMenu* show = newMenu(i18n("Show"), this); show->setIcon(Icon_Utils::SmallIcon(Icon_Utils::it_Show)); KMenu* attributes = newMenu(i18n("Attributes"), this); if (type == WidgetBase::wt_Class) { insert(mt_Show_Attributes_Selection, attributes, i18n("Show")); insert(mt_Hide_Attributes_Selection, attributes, i18n("Hide")); insert(mt_Show_Attribute_Signature_Selection, attributes, i18n("Show Signatures")); insert(mt_Hide_Attribute_Signature_Selection, attributes, i18n("Hide Signatures")); } show->addMenu(attributes); KMenu* operations = newMenu(i18n("Operations"), this); insert(mt_Show_Operations_Selection, operations, i18n("Show")); insert(mt_Hide_Operations_Selection, operations, i18n("Hide")); insert(mt_Show_Operation_Signature_Selection, operations, i18n("Show Signatures")); insert(mt_Hide_Operation_Signature_Selection, operations, i18n("Hide Signatures")); show->addMenu(operations); KMenu* visibility = newMenu(i18n("Visibility"), this); insert(mt_Show_Visibility_Selection, visibility, i18n("Show")); insert(mt_Hide_Visibility_Selection, visibility, i18n("Hide")); insert(mt_Hide_NonPublic_Selection, visibility, i18n("Hide Non-public members")); insert(mt_Show_NonPublic_Selection, visibility, i18n("Show Non-public members")); show->addMenu(visibility); KMenu* packages = newMenu(i18n("Packages"), this); insert(mt_Show_Packages_Selection, packages, i18n("Show")); insert(mt_Hide_Packages_Selection, packages, i18n("Hide")); show->addMenu(packages); if (type == WidgetBase::wt_Class) { KMenu* stereotypes = newMenu(i18n("Stereotypes"), this); insert(mt_Show_Stereotypes_Selection, stereotypes, i18n("Show")); insert(mt_Hide_Stereotypes_Selection, stereotypes, i18n("Hide")); show->addMenu(stereotypes); } addMenu(show); } /** * Inserts the menu actions for a widget * * @param widget widget to generate the menu for */ void WidgetBasePopupMenu::insertSingleSelectionMenu(WidgetBase* widget) { WidgetBase::WidgetType type = widget->baseType(); switch (type) { case WidgetBase::wt_Actor: case WidgetBase::wt_UseCase: insertSubMenuNew(type); insertSubMenuColor(widget->useFillColor()); insertStdItems(true, type); insert(mt_Rename); insert(mt_Change_Font); insert(mt_Properties); break; case WidgetBase::wt_Category: { insertSubMenuNew(type); insertSubMenuCategoryType(widget->umlObject()->asUMLCategory()); insertSubMenuColor(widget->useFillColor()); insertStdItems(true, type); insert(mt_Rename); insert(mt_Change_Font); break; } case WidgetBase::wt_Class: { ClassifierWidget* c = widget->asClassifierWidget(); if (!c) break; insertSubMenuNew(type); makeClassifierShowPopup(c); insertSubMenuColor(c->useFillColor()); insertStdItems(true, type); insert(mt_Rename); insert(mt_Change_Font); if (c->umlObject() && c->umlObject()->stereotype() == QLatin1String("class-or-package")) { insert(mt_ChangeToClass, i18n("Change into Class")); insert(mt_ChangeToPackage, i18n("Change into Package")); } else { insert(mt_Refactoring, Icon_Utils::SmallIcon(Icon_Utils::it_Refactor), i18n("Refactor")); insert(mt_ViewCode, Icon_Utils::SmallIcon(Icon_Utils::it_View_Code), i18n("View Code")); UMLClassifier *umlc = c->classifier(); if (umlc->isAbstract() && umlc->getAttributeList().size() == 0) insert(mt_ChangeToInterface, i18n("Change into Interface")); } insert(mt_Properties); } break; case WidgetBase::wt_Interface: { - ClassifierWidget* c = widget->asClassifierWidget(); + InterfaceWidget* c = widget->asInterfaceWidget(); if (!c) break; insertSubMenuNew(type); makeClassifierShowPopup(c); insertSubMenuColor(c->useFillColor()); insertStdItems(true, type); insert(mt_Rename); insert(mt_Change_Font); insert(mt_DrawAsCircle, i18n("Draw as Circle"), CHECKABLE); setActionChecked(mt_DrawAsCircle, c->visualProperty(ClassifierWidget::DrawAsCircle)); insert(mt_ChangeToClass, i18n("Change into Class")); insert(mt_Properties); } break; case WidgetBase::wt_Instance: insertSubMenuNew(type); insert(mt_InstanceAttribute); insert(mt_Rename_Object); insert(mt_Rename, i18n("Rename Class...")); insertStdItems(true, type); insert(mt_Change_Font); insert(mt_Properties); break; case WidgetBase::wt_Enum: insertSubMenuNew(type); insertSubMenuColor(widget->useFillColor()); insertStdItems(true, type); insert(mt_Rename); insert(mt_Change_Font); insert(mt_Properties); break; case WidgetBase::wt_Entity: insertSubMenuNew(type); insertSubMenuShowEntity(widget->asEntityWidget()); insertSubMenuColor(widget->useFillColor()); insertStdItems(true, type); insert(mt_Rename); insert(mt_Change_Font); insert(mt_Properties); break; case WidgetBase::wt_Datatype: case WidgetBase::wt_Package: case WidgetBase::wt_Component: case WidgetBase::wt_Node: case WidgetBase::wt_Artifact: insertSubMenuNew(type); insertSubMenuColor(widget->useFillColor()); insertStdItems(false, type); insert(mt_Rename); insert(mt_Change_Font); insert(mt_Properties); break; case WidgetBase::wt_Port: insertSubMenuNew(type); insertSubMenuColor(widget->useFillColor()); insertStdItems(false); insert(mt_NameAsTooltip, i18n("Name as Tooltip"), true); { PinPortBase *pW = static_cast(widget); FloatingTextWidget *ft = pW->floatingTextWidget(); if (ft == 0) m_actions[mt_NameAsTooltip]->setChecked(true); } insert(mt_Delete); insert(mt_Properties); break; case WidgetBase::wt_Object: //Used for sequence diagram and collaboration diagram widgets insertSubMenuNew(type); insertSubMenuColor(widget->useFillColor()); if (widget->umlScene() && widget->umlScene()->type() == Uml::DiagramType::Sequence) { addSeparator(); MenuType tabUp = mt_Up; insert(mt_Up, Icon_Utils::SmallIcon(Icon_Utils::it_Arrow_Up), i18n("Move Up")); insert(mt_Down, Icon_Utils::SmallIcon(Icon_Utils::it_Arrow_Down), i18n("Move Down")); if (!(static_cast(widget))->canTabUp()) { setActionEnabled(tabUp, false); } } insertStdItems(true, type); insert(mt_Rename_Object); insert(mt_Rename, i18n("Rename Class...")); insert(mt_Change_Font); insert(mt_Properties); break; case WidgetBase::wt_Message: insertSubMenuNew(type); insertSubMenuColor(widget->useFillColor()); insertStdItems(false, type); //insert(mt_Change_Font); //insert(mt_Operation, Icon_Utils::SmallIcon(Icon_Utils::it_Operation_New), i18n("New Operation...")); //insert(mt_Select_Operation, i18n("Select Operation...")); break; case WidgetBase::wt_Note: insertSubMenuNew(type); insertSubMenuColor(widget->useFillColor()); addSeparator(); insert(mt_Cut); insert(mt_Copy); insert(mt_Paste); insert(mt_Clear, Icon_Utils::SmallIcon(Icon_Utils::it_Clear), i18nc("clear note", "Clear")); addSeparator(); insert(mt_Rename, i18n("Change Text...")); insert(mt_Resize); insert(mt_AutoResize, i18n("Auto resize"), CHECKABLE); insert(mt_Delete); insert(mt_Change_Font); insert(mt_Properties); break; case WidgetBase::wt_Box: insertSubMenuNew(type); insertStdItems(false, type); insert(mt_Line_Color); break; case WidgetBase::wt_State: { StateWidget* pState = static_cast< StateWidget *>(widget); if (pState->stateType() == StateWidget::Normal) { // FIXME: why not using wt_state insertSubMenuNew(WidgetBase::wt_Activity); } else { insertSubMenuNew(type); } insertSubMenuColor(widget->useFillColor()); insertStdItems(false, type); switch (pState->stateType()) { case StateWidget::Normal: insert(mt_Rename, i18n("Change State Name...")); insert(mt_Change_Font); insert(mt_Properties); break; case StateWidget::Fork: case StateWidget::Join: if (pState->drawVertical()) insert(mt_Flip, i18n("Flip Horizontal")); else insert(mt_Flip, i18n("Flip Vertical")); break; default: break; } } break; case WidgetBase::wt_ForkJoin: insertSubMenuNew(type); { ForkJoinWidget *pForkJoin = static_cast(widget); if (pForkJoin->orientation() == Qt::Vertical) { insert(mt_Flip, i18n("Flip Horizontal")); } else { insert(mt_Flip, i18n("Flip Vertical")); } m_actions[mt_Fill_Color] = addAction(Icon_Utils::SmallIcon(Icon_Utils::it_Color_Fill), i18n("Fill Color...")); } break; case WidgetBase::wt_Activity: insertSubMenuNew(type); { ActivityWidget* pActivity = static_cast(widget); if(pActivity->activityType() == ActivityWidget::Normal || pActivity->activityType() == ActivityWidget::Invok || pActivity->activityType() == ActivityWidget::Param) { insertSubMenuColor(widget->useFillColor()); } insertStdItems(false, type); if(pActivity->activityType() == ActivityWidget::Normal || pActivity->activityType() == ActivityWidget::Invok || pActivity->activityType() == ActivityWidget::Param) { insert(mt_Rename, i18n("Change Activity Name...")); insert(mt_Change_Font); insert(mt_Properties); } } break; case WidgetBase::wt_ObjectNode: insertSubMenuNew(type); { ObjectNodeWidget* objWidget = static_cast(widget); if (objWidget->objectNodeType() == ObjectNodeWidget::Buffer || objWidget->objectNodeType() == ObjectNodeWidget::Data || objWidget->objectNodeType() == ObjectNodeWidget::Flow) { insertSubMenuColor(widget->useFillColor()); } insertStdItems(false, type); if (objWidget->objectNodeType() == ObjectNodeWidget::Buffer || objWidget->objectNodeType() == ObjectNodeWidget::Data || objWidget->objectNodeType() == ObjectNodeWidget::Flow) { insert(mt_Rename, i18n("Change Object Node Name...")); insert(mt_Change_Font); insert(mt_Properties); } } break; case WidgetBase::wt_Pin: case WidgetBase::wt_Signal: case WidgetBase::wt_FloatingDashLine: case WidgetBase::wt_Precondition: insertSubMenuNew(type); insertSubMenuColor(widget->useFillColor()); addSeparator(); insert(mt_Cut); insert(mt_Copy); insert(mt_Paste); insert(mt_Clear, Icon_Utils::SmallIcon(Icon_Utils::it_Clear), i18nc("clear precondition", "Clear")); addSeparator(); insert(mt_Rename, i18n("Change Text...")); if (type == WidgetBase::wt_Pin) { insert(mt_NameAsTooltip, i18n("Name as Tooltip"), true); PinPortBase *pW = static_cast(widget); FloatingTextWidget *ft = pW->floatingTextWidget(); if (ft == 0) m_actions[mt_NameAsTooltip]->setChecked(true); } insert(mt_Delete); insert(mt_Change_Font); break; case WidgetBase::wt_CombinedFragment: insertSubMenuNew(type); // for alternative and parallel combined fragments if ((static_cast(widget))->combinedFragmentType() == CombinedFragmentWidget::Alt || (static_cast(widget))->combinedFragmentType() == CombinedFragmentWidget::Par) { insert(mt_AddInteractionOperand, i18n("Add Interaction Operand")); addSeparator(); } insertSubMenuColor(widget->useFillColor()); addSeparator(); insert(mt_Cut); insert(mt_Copy); insert(mt_Paste); insert(mt_Clear, Icon_Utils::SmallIcon(Icon_Utils::it_Clear), i18nc("clear combined fragment", "Clear")); addSeparator(); insert(mt_Rename, i18n("Change Text...")); insert(mt_Delete); insert(mt_Change_Font); break; case WidgetBase::wt_Text: insertSubMenuNew(type); switch((static_cast(widget))->textRole()) { case Uml::TextRole::MultiB: insertAssociationTextItem(i18n("Change Multiplicity..."), mt_Rename_MultiB); break; case Uml::TextRole::MultiA: insertAssociationTextItem(i18n("Change Multiplicity..."), mt_Rename_MultiA); break; case Uml::TextRole::Name: insertAssociationTextItem(i18n("Change Name"), mt_Rename_Name); break; case Uml::TextRole::RoleAName: insertAssociationTextItem(i18n("Change Role A Name..."), mt_Rename_RoleAName); break; case Uml::TextRole::RoleBName: insertAssociationTextItem(i18n("Change Role B Name..."), mt_Rename_RoleBName); break; case Uml::TextRole::ChangeA: case Uml::TextRole::ChangeB: insert(mt_Change_Font); insert(mt_Reset_Label_Positions); insert(mt_Properties); break; case Uml::TextRole::Coll_Message_Self: case Uml::TextRole::Coll_Message: case Uml::TextRole::Seq_Message_Self: case Uml::TextRole::Seq_Message: insert(mt_Change_Font); insert(mt_Operation, Icon_Utils::SmallIcon(Icon_Utils::it_Operation_New), i18n("New Operation...")); insert(mt_Select_Operation, i18n("Select Operation...")); break; case Uml::TextRole::Floating: default: insertStdItems(false, type); insert(mt_Rename, i18n("Change Text...")); insert(mt_Change_Font); break; } break; default: uWarning() << "unhandled WidgetType " << WidgetBase::toString(type); break; }//end switch } /** * Inserts the menu actions that work on the whole selection of widgets */ void WidgetBasePopupMenu::insertMultiSelectionMenu(WidgetBase::WidgetType uniqueType) { insertSubMenuAlign(); KMenu* color = newMenu(i18nc("color menu", "Color"), this); insert(mt_Line_Color_Selection, color, Icon_Utils::SmallIcon(Icon_Utils::it_Color_Line), i18n("Line Color...")); insert(mt_Fill_Color_Selection, color, Icon_Utils::SmallIcon(Icon_Utils::it_Color_Fill), i18n("Fill Color...")); insert(mt_Set_Use_Fill_Color_Selection, color, i18n("Use Fill Color")); insert(mt_Unset_Use_Fill_Color_Selection, color, i18n("No Fill Color")); // Add menu actions specific to classifiers if (uniqueType == WidgetBase::wt_Class || uniqueType == WidgetBase::wt_Interface) { makeMultiClassifierShowPopup(uniqueType); } addMenu(color); addSeparator(); insert(mt_Cut); insert(mt_Copy); addSeparator(); insert(mt_Clone); insert(mt_Delete); insert(mt_Resize); addSeparator(); insert(mt_Change_Font_Selection, Icon_Utils::SmallIcon(Icon_Utils::it_Change_Font), i18n("Change Font...")); } /** * Shortcut for the frequently used insert() calls. * * @param insertLeadingSeparator Set this true if the group shall * start with a separator. * @param type The WidgetType for which to insert the menu items. * If no argument is supplied then a Rename item will be * included. */ void WidgetBasePopupMenu::insertStdItems(bool insertLeadingSeparator, WidgetBase::WidgetType type) { if (insertLeadingSeparator) addSeparator(); insert(mt_Cut); insert(mt_Copy); insert(mt_Paste); addSeparator(); if (type == WidgetBase::wt_UMLWidget) insert(mt_Rename); else if (Model_Utils::isCloneable(type)) { insert(mt_Clone); insert(mt_Remove); } else insert(mt_Delete); insert(mt_Resize); insert(mt_AutoResize, i18n("Auto resize"), CHECKABLE); } /** * Add the align actions submenu */ void WidgetBasePopupMenu::insertSubMenuAlign() { KMenu* alignment = newMenu(i18nc("align menu", "Align"), this); insert(mt_Align_Right, alignment, Icon_Utils::SmallIcon(Icon_Utils::it_Align_Right), i18n("Align Right")); insert(mt_Align_Left, alignment, Icon_Utils::SmallIcon(Icon_Utils::it_Align_Left), i18n("Align Left")); insert(mt_Align_Top, alignment, Icon_Utils::SmallIcon(Icon_Utils::it_Align_Top), i18n("Align Top")); insert(mt_Align_Bottom, alignment, Icon_Utils::SmallIcon(Icon_Utils::it_Align_Bottom), i18n("Align Bottom")); insert(mt_Align_VerticalMiddle, alignment, Icon_Utils::SmallIcon(Icon_Utils::it_Align_VerticalMiddle), i18n("Align Vertical Middle")); insert(mt_Align_HorizontalMiddle, alignment, Icon_Utils::SmallIcon(Icon_Utils::it_Align_HorizontalMiddle), i18n("Align Horizontal Middle")); insert(mt_Align_VerticalDistribute, alignment, Icon_Utils::SmallIcon(Icon_Utils::it_Align_VerticalDistribute), i18n("Align Vertical Distribute")); insert(mt_Align_HorizontalDistribute, alignment, Icon_Utils::SmallIcon(Icon_Utils::it_Align_HorizontalDistribute), i18n("Align Horizontal Distribute")); addMenu(alignment); } /** * Shortcut for commonly used sub menu initializations. * * @param fc The "Use Fill Color" is checked. */ void WidgetBasePopupMenu::insertSubMenuColor(bool fc) { KMenu* color = newMenu(i18nc("color menu", "Color"), this); insert(mt_Line_Color, color, Icon_Utils::SmallIcon(Icon_Utils::it_Color_Line), i18n("Line Color...")); insert(mt_Fill_Color, color, Icon_Utils::SmallIcon(Icon_Utils::it_Color_Fill), i18n("Fill Color...")); insert(mt_Use_Fill_Color, color, i18n("Use Fill Color"), CHECKABLE); setActionChecked(mt_Use_Fill_Color, fc); addMenu(color); } /** * Shortcut for commonly used sub menu initializations. * * @param type The widget type for which to set up the menu. */ void WidgetBasePopupMenu::insertSubMenuNew(WidgetBase::WidgetType type, KMenu *menu) { if (!menu) menu = makeNewMenu(); switch (type) { case WidgetBase::wt_Actor: case WidgetBase::wt_UseCase: insert(mt_Actor, menu); insert(mt_UseCase, menu); break; case WidgetBase::wt_Component: insert(mt_Component, menu); if (Settings::optionState().generalState.uml2) insert(mt_Port, menu); insert(mt_Artifact, menu); break; case WidgetBase::wt_Class: insert(mt_Attribute, menu); insert(mt_Operation, menu); insert(mt_Template, menu); insert(mt_Class, menu); insert(mt_Interface, menu); insert(mt_Datatype, menu); insert(mt_Enum, menu); break; case WidgetBase::wt_Interface: insert(mt_Operation, menu); insert(mt_Template, menu); insert(mt_Class, menu); insert(mt_Interface, menu); insert(mt_Datatype, menu); insert(mt_Enum, menu); break; case WidgetBase::wt_Entity: insert(mt_EntityAttribute, menu); insert(mt_PrimaryKeyConstraint, menu); insert(mt_UniqueConstraint, menu); insert(mt_ForeignKeyConstraint, menu); insert(mt_CheckConstraint, menu); break; case WidgetBase::wt_Enum: insert(mt_EnumLiteral, menu); break; default: break; } insert(mt_Note, menu); insert(mt_FloatText, menu); addMenu(menu); } void WidgetBasePopupMenu::insertSubMenuShowEntity(EntityWidget *widget) { KMenu* show = newMenu(i18n("Show"), this); show->setIcon(Icon_Utils::SmallIcon(Icon_Utils::it_Show)); insert(mt_Show_Attribute_Signature, show, i18n("Attribute Signature"), CHECKABLE); setActionChecked(mt_Show_Attribute_Signature, widget->showAttributeSignature()); insert(mt_Show_Stereotypes, show, i18n("Stereotype"), CHECKABLE); setActionChecked(mt_Show_Stereotypes, widget->showStereotype()); addMenu(show); } diff --git a/umbrello/model_utils.cpp b/umbrello/model_utils.cpp index 992baead3..4e2ff8bb2 100644 --- a/umbrello/model_utils.cpp +++ b/umbrello/model_utils.cpp @@ -1,2129 +1,2130 @@ /*************************************************************************** * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * copyright (C) 2004-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "model_utils.h" // app includes #include "floatingtextwidget.h" #include "debug_utils.h" #include "umlobject.h" #include "umlpackagelist.h" #include "uniqueconstraint.h" #include "package.h" #include "folder.h" #include "classifier.h" #include "enum.h" #include "entity.h" #include "template.h" #include "operation.h" #include "attribute.h" #include "association.h" #include "umlrole.h" #include "umldoc.h" #include "uml.h" #include "umllistview.h" #include "umllistviewitem.h" #include "umlscene.h" #include "umlview.h" #include "codegenerator.h" // kde includes #include // qt includes #include #include namespace Model_Utils { /** * Determines whether the given widget type is cloneable. * * @param type The input WidgetType. * @return True if the given type is cloneable. */ bool isCloneable(WidgetBase::WidgetType type) { switch (type) { case WidgetBase::wt_Actor: case WidgetBase::wt_UseCase: case WidgetBase::wt_Class: case WidgetBase::wt_Interface: case WidgetBase::wt_Enum: case WidgetBase::wt_Datatype: case WidgetBase::wt_Package: case WidgetBase::wt_Component: case WidgetBase::wt_Port: case WidgetBase::wt_Node: case WidgetBase::wt_Artifact: case WidgetBase::wt_Instance: case WidgetBase::wt_Entity: return true; default: return false; } } /** * Seek the given id in the given list of objects. * Each list element may itself contain other objects * and the search is done recursively. * * @param id The unique ID to seek. * @param inList The UMLObjectList in which to search. * @return Pointer to the UMLObject that matches the ID (NULL if none matches). */ UMLObject* findObjectInList(Uml::ID::Type id, const UMLObjectList& inList) { for (UMLObjectListIt oit(inList); oit.hasNext();) { UMLObject *obj = oit.next(); + uIgnoreZeroPointer(obj); if (obj->id() == id) return obj; UMLObject *o; UMLObject::ObjectType t = obj->baseType(); switch (t) { case UMLObject::ot_Folder: case UMLObject::ot_Package: case UMLObject::ot_Component: o = obj->asUMLPackage()->findObjectById(id); if (o) return o; break; case UMLObject::ot_Interface: case UMLObject::ot_Class: case UMLObject::ot_Enum: case UMLObject::ot_Entity: case UMLObject::ot_Instance: o = obj->asUMLClassifier()->findChildObjectById(id); if (o == 0 && (t == UMLObject::ot_Interface || t == UMLObject::ot_Class)) o = ((UMLPackage*)obj)->findObjectById(id); if (o) return o; break; case UMLObject::ot_Association: { UMLAssociation *assoc = obj->asUMLAssociation(); UMLRole *rA = assoc->getUMLRole(Uml::RoleType::A); if (rA->id() == id) return rA; UMLRole *rB = assoc->getUMLRole(Uml::RoleType::B); if (rB->id() == id) return rB; } break; default: break; } } return 0; } /** * Find the UML object of the given type and name in the passed-in list. * * @param inList List in which to seek the object. * @param inName Name of the object to find. * @param type ObjectType of the object to find (optional.) * When the given type is ot_UMLObject the type is * disregarded, i.e. the given name is the only * search criterion. * @param currentObj Object relative to which to search (optional.) * If given then the enclosing scope(s) of this * object are searched before the global scope. * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* findUMLObject(const UMLObjectList& inList, const QString& inName, UMLObject::ObjectType type /* = ot_UMLObject */, UMLObject *currentObj /* = 0 */) { const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); QString name = inName; const bool atGlobalScope = name.startsWith(QLatin1String("::")); if (atGlobalScope) { name = name.mid(2); currentObj = 0; } QStringList components; #ifdef TRY_BUGFIX_120682 // If we have a pointer or a reference in cpp we need to remove // the asterisks and ampersands in order to find the appropriate object if (UMLApp::app()->getActiveLanguage() == Uml::pl_Cpp) { if (name.endsWith(QLatin1Char('*'))) name.remove(QLatin1Char('*')); else if (name.contains(QLatin1Char('&'))) name.remove(QLatin1Char('&')); } #endif QString scopeSeparator = UMLApp::app()->activeLanguageScopeSeparator(); if (name.contains(scopeSeparator)) components = name.split(scopeSeparator); QString nameWithoutFirstPrefix; if (components.size() > 1) { name = components.front(); components.pop_front(); nameWithoutFirstPrefix = components.join(scopeSeparator); } if (currentObj) { UMLPackage *pkg = 0; if (currentObj->asUMLClassifierListItem()) { currentObj = currentObj->umlParent(); } pkg = currentObj->asUMLPackage(); if (pkg == 0 || pkg->baseType() == UMLObject::ot_Association) pkg = currentObj->umlPackage(); // Remember packages that we've seen - for avoiding cycles. UMLPackageList seenPkgs; for (; pkg; pkg = currentObj->umlPackage()) { if (nameWithoutFirstPrefix.isEmpty() && (type == UMLObject::ot_UMLObject || type == UMLObject::ot_Folder || type == UMLObject::ot_Package || type == pkg->baseType())) { if (caseSensitive) { if (pkg->name() == name) return pkg; } else if (pkg->name().toLower() == name.toLower()) { return pkg; } } if (seenPkgs.indexOf(pkg) != -1) { uError() << "findUMLObject(" << name << "): " << "breaking out of cycle involving " << pkg->name(); break; } seenPkgs.append(pkg); // exclude non package type // pg->asUMLPackage() fails for unknown reason // see https://bugs.kde.org/show_bug.cgi?id=341709 UMLObject::ObjectType foundType = pkg->baseType(); if (foundType != UMLObject::ot_Package && foundType != UMLObject::ot_Folder && foundType != UMLObject::ot_Class && foundType != UMLObject::ot_Interface && foundType != UMLObject::ot_Component) { continue; } UMLObjectList &objectsInCurrentScope = pkg->containedObjects(); for (UMLObjectListIt oit(objectsInCurrentScope); oit.hasNext();) { UMLObject *obj = oit.next(); uIgnoreZeroPointer(obj); if (caseSensitive) { if (obj->name() != name) continue; } else if (obj->name().toLower() != name.toLower()) { continue; } UMLObject::ObjectType foundType = obj->baseType(); if (nameWithoutFirstPrefix.isEmpty()) { if (type != UMLObject::ot_UMLObject && type != foundType) { uDebug() << "type mismatch for " << name << " (seeking type: " << UMLObject::toString(type) << ", found type: " << UMLObject::toString(foundType) << ")"; // Class, Interface, and Datatype are all Classifiers // and are considered equivalent. // The caller must be prepared to handle possible mismatches. if ((type == UMLObject::ot_Class || type == UMLObject::ot_Interface || type == UMLObject::ot_Datatype) && (foundType == UMLObject::ot_Class || foundType == UMLObject::ot_Interface || foundType == UMLObject::ot_Datatype)) { return obj; } continue; } return obj; } if (foundType != UMLObject::ot_Package && foundType != UMLObject::ot_Folder && foundType != UMLObject::ot_Class && foundType != UMLObject::ot_Interface && foundType != UMLObject::ot_Component) { uDebug() << "found " << UMLObject::toString(foundType) << name << " is not a package (?)"; continue; } UMLPackage *pkg = obj->asUMLPackage(); return findUMLObject(pkg->containedObjects(), nameWithoutFirstPrefix, type); } currentObj = pkg; } } for (UMLObjectListIt oit(inList); oit.hasNext();) { UMLObject *obj = oit.next(); uIgnoreZeroPointer(obj); if (caseSensitive) { if (obj->name() != name) continue; } else if (obj->name().toLower() != name.toLower()) { continue; } UMLObject::ObjectType foundType = obj->baseType(); if (nameWithoutFirstPrefix.isEmpty()) { if (type != UMLObject::ot_UMLObject && type != foundType) { uDebug() << "type mismatch for " << name << " (seeking type: " << UMLObject::toString(type) << ", found type: " << UMLObject::toString(foundType) << ")"; continue; } return obj; } if (foundType != UMLObject::ot_Package && foundType != UMLObject::ot_Folder && foundType != UMLObject::ot_Class && foundType != UMLObject::ot_Interface && foundType != UMLObject::ot_Component) { uDebug() << "found " << name << "(" << UMLObject::toString(foundType) << ")" << " is not a package (?)"; continue; } UMLPackage *pkg = obj->asUMLPackage(); return findUMLObject(pkg->containedObjects(), nameWithoutFirstPrefix, type); } return 0; } /** * Find the UML object of the given type and name in the passed-in list. * This method searches for the raw name. * * @param inList List in which to seek the object. * @param name Name of the object to find. * @param type ObjectType of the object to find (optional.) * When the given type is ot_UMLObject the type is * disregarded, i.e. the given name is the only * search criterion. * @param currentObj Object relative to which to search (optional.) * If given then the enclosing scope(s) of this * object are searched before the global scope. * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* findUMLObjectRaw(const UMLObjectList& inList, const QString& name, UMLObject::ObjectType type /* = ot_UMLObject */, UMLObject *currentObj /*= 0*/) { Q_UNUSED(currentObj); for (UMLObjectListIt oit(inList); oit.hasNext();) { UMLObject *obj = oit.next(); if (obj->name() == name && type == obj->baseType()) return obj; } return 0; } /** * Find the UML object of the given type and name in the passed-in list. * This method searches for the raw name. * * @param inList List in which to seek the object. * @param name Name of the object to find. * @param type ObjectType of the object to find (optional.) * When the given type is ot_UMLObject the type is * disregarded, i.e. the given name is the only * search criterion. * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* findUMLObjectRecursive(const UMLObjectList& inList, const QString& name, UMLObject::ObjectType type /* = ot_UMLObject */) { foreach(UMLObject *obj, inList) { if (obj->name() == name && type == obj->baseType()) return obj; UMLPackage *pkg = obj->asUMLPackage(); if (pkg && pkg->containedObjects().size() > 0) { UMLObject *o = findUMLObjectRecursive(pkg->containedObjects(), name, type); if (o) return o; } } return 0; } /** * Get the root folder of the given UMLObject. */ UMLPackage* rootPackage(UMLObject* obj) { if (obj == 0) return 0; UMLPackage* root = obj->umlPackage(); if (root == 0) { root = obj->asUMLPackage(); } else { while (root->umlPackage() != 0) { root = root->umlPackage(); } } return root; } /** * Add the given list of views to the tree view. * @param viewList the list of views to add */ void treeViewAddViews(const UMLViewList& viewList) { UMLListView* tree = UMLApp::app()->listView(); foreach (UMLView* v, viewList) { if (tree->findItem(v->umlScene()->ID()) != 0) { continue; } tree->createDiagramItem(v); } } /** * Change an icon of an object in the tree view. * @param object the object in the treeViewAddViews * @param to the new icon type for the given object */ void treeViewChangeIcon(UMLObject* object, Icon_Utils::IconType to) { UMLListView* tree = UMLApp::app()->listView(); tree->changeIconOf(object, to); } /** * Set the given object to the current item in the tree view. * @param object the object which will be the current item */ void treeViewSetCurrentItem(UMLObject* object) { UMLListView* tree = UMLApp::app()->listView(); UMLListViewItem* item = tree->findUMLObject(object); tree->setCurrentItem(item); } /** * Move an object to a new container in the tree view. * @param container the new container for the object * @param object the to be moved object */ void treeViewMoveObjectTo(UMLObject* container, UMLObject* object) { UMLListView *listView = UMLApp::app()->listView(); UMLListViewItem *newParent = listView->findUMLObject(container); listView->moveObject(object->id(), Model_Utils::convert_OT_LVT(object), newParent); } /** * Return the current UMLObject from the tree view. * @return the UML object of the current item */ UMLObject* treeViewGetCurrentObject() { UMLListView *listView = UMLApp::app()->listView(); UMLListViewItem *current = static_cast(listView->currentItem()); return current->umlObject(); } /** * Return the UMLPackage if the current item * in the tree view is a package. Return the * closest package in the tree view or NULL otherwise * * @return the package or NULL */ UMLPackage* treeViewGetPackageFromCurrent() { UMLListView *listView = UMLApp::app()->listView(); UMLListViewItem *parentItem = (UMLListViewItem*)listView->currentItem(); while (parentItem) { UMLListViewItem::ListViewType lvt = parentItem->type(); if (Model_Utils::typeIsContainer(lvt)) { UMLObject *o = parentItem->umlObject(); return o->asUMLPackage(); } // selected item is not a container, try to find the // container higher up in the tree view parentItem = static_cast(parentItem->parent()); } return 0; } /** * Build the diagram name from the tree view. * The function returns a relative path constructed from the folder hierarchy. * @param id the id of the diaram * @return the constructed diagram name */ QString treeViewBuildDiagramName(Uml::ID::Type id) { UMLListView *listView = UMLApp::app()->listView(); UMLListViewItem* listViewItem = listView->findItem(id); if (listViewItem) { QString name = listViewItem->text(0); listViewItem = static_cast(listViewItem->parent()); // Relies on the tree structure of the UMLListView. There are a base "Views" folder // and five children, one for each view type (Logical, use case, components, deployment // and entity relationship) while (listView->rootView(listViewItem->type()) == 0) { name.insert(0, listViewItem->text(0) + QLatin1Char('/')); listViewItem = static_cast(listViewItem->parent()); if (listViewItem == 0) break; } return name; } else { uWarning() << "diagram not found - returning empty name!"; return QString(); } } /** * Returns a name for the new object, appended with a number * if the default name is taken e.g. new_actor, new_actor_1 * etc. * @param type The object type. * @param parentPkg The package in which to compare the name. * @param prefix The prefix to use (optional) * If no prefix is given then a type related * prefix will be chosen internally. */ QString uniqObjectName(UMLObject::ObjectType type, UMLPackage *parentPkg, QString prefix) { QString currentName = prefix; if (currentName.isEmpty()) { if(type == UMLObject::ot_Class) currentName = i18n("new_class"); else if(type == UMLObject::ot_Actor) currentName = i18n("new_actor"); else if(type == UMLObject::ot_UseCase) currentName = i18n("new_usecase"); else if(type == UMLObject::ot_Package) currentName = i18n("new_package"); else if(type == UMLObject::ot_Component) currentName = i18n("new_component"); else if(type == UMLObject::ot_Port) currentName = i18n("new_port"); else if(type == UMLObject::ot_Node) currentName = i18n("new_node"); else if(type == UMLObject::ot_Artifact) currentName = i18n("new_artifact"); else if(type == UMLObject::ot_Interface) currentName = i18n("new_interface"); else if(type == UMLObject::ot_Datatype) currentName = i18n("new_datatype"); else if(type == UMLObject::ot_Enum) currentName = i18n("new_enum"); else if(type == UMLObject::ot_Entity) currentName = i18n("new_entity"); else if(type == UMLObject::ot_Folder) currentName = i18n("new_folder"); else if(type == UMLObject::ot_Association) currentName = i18n("new_association"); else if(type == UMLObject::ot_Category) currentName = i18n("new_category"); else if(type == UMLObject::ot_Instance) currentName = i18n("new_object"); else { currentName = i18n("new_object"); uWarning() << "unknown object type in umldoc::uniqObjectName()"; } } UMLDoc *doc = UMLApp::app()->document(); QString name = currentName; for (int number = 1; !doc->isUnique(name, parentPkg); ++number) { name = currentName + QLatin1Char('_') + QString::number(number); } return name; } /** * Return the xmi.id (XMI-1) or xmi:id (XMI-2) of a QDomElement. */ QString getXmiId(QDomElement element) { QString idStr = element.attribute(QLatin1String("xmi.id")); if (idStr.isEmpty()) idStr = element.attribute(QLatin1String("xmi:id")); return idStr; } /** * Return true if the given tag is one of the common XMI * attributes, such as: * "name" | "visibility" | "isRoot" | "isLeaf" | "isAbstract" | * "isActive" | "ownerScope" */ bool isCommonXMI1Attribute(const QString &tag) { bool retval = (UMLDoc::tagEq(tag, QLatin1String("name")) || UMLDoc::tagEq(tag, QLatin1String("visibility")) || UMLDoc::tagEq(tag, QLatin1String("isRoot")) || UMLDoc::tagEq(tag, QLatin1String("isLeaf")) || UMLDoc::tagEq(tag, QLatin1String("isAbstract")) || UMLDoc::tagEq(tag, QLatin1String("isSpecification")) || UMLDoc::tagEq(tag, QLatin1String("isActive")) || UMLDoc::tagEq(tag, QLatin1String("namespace")) || UMLDoc::tagEq(tag, QLatin1String("ownerScope")) || UMLDoc::tagEq(tag, QLatin1String("ModelElement.stereotype")) || UMLDoc::tagEq(tag, QLatin1String("GeneralizableElement.generalization")) || UMLDoc::tagEq(tag, QLatin1String("specialization")) || //NYI UMLDoc::tagEq(tag, QLatin1String("clientDependency")) || //NYI UMLDoc::tagEq(tag, QLatin1String("supplierDependency")) //NYI ); return retval; } /** * Return true if the given type is common among the majority * of programming languages, such as "bool" or "boolean". * TODO: Make this depend on the active programming language. */ bool isCommonDataType(QString type) { CodeGenerator *gen = UMLApp::app()->generator(); if (gen == 0) return false; const bool caseSensitive = UMLApp::app()->activeLanguageIsCaseSensitive(); const QStringList dataTypes = gen->defaultDatatypes(); QStringList::ConstIterator end(dataTypes.end()); for (QStringList::ConstIterator it = dataTypes.begin(); it != end; ++it) { if (caseSensitive) { if (type == *it) return true; } else if (type.toLower() == (*it).toLower()) { return true; } } return false; } /** * Return true if the given object type is a classifier list item type. */ bool isClassifierListitem(UMLObject::ObjectType type) { if (type == UMLObject::ot_Attribute || type == UMLObject::ot_Operation || type == UMLObject::ot_Template || type == UMLObject::ot_EntityAttribute || type == UMLObject::ot_EnumLiteral || type == UMLObject::ot_UniqueConstraint || type == UMLObject::ot_ForeignKeyConstraint || type == UMLObject::ot_CheckConstraint || type == UMLObject::ot_InstanceAttribute ) { return true; } else { return false; } } /** * Try to guess the correct container folder type of an UMLObject. * Object types that can't be guessed are mapped to Uml::ModelType::Logical. * NOTE: This function exists mainly for handling pre-1.5.5 files * and should not be used for new code. */ Uml::ModelType::Enum guessContainer(UMLObject *o) { UMLObject::ObjectType ot = o->baseType(); if (ot == UMLObject::ot_Package && o->stereotype() == QLatin1String("subsystem")) return Uml::ModelType::Component; Uml::ModelType::Enum mt = Uml::ModelType::N_MODELTYPES; switch (ot) { case UMLObject::ot_Package: // trouble: package can also appear in Component view case UMLObject::ot_Interface: case UMLObject::ot_Datatype: case UMLObject::ot_Enum: case UMLObject::ot_Class: case UMLObject::ot_Attribute: case UMLObject::ot_Operation: case UMLObject::ot_EnumLiteral: case UMLObject::ot_Template: case UMLObject::ot_Instance: case UMLObject::ot_InstanceAttribute: mt = Uml::ModelType::Logical; break; case UMLObject::ot_Actor: case UMLObject::ot_UseCase: mt = Uml::ModelType::UseCase; break; case UMLObject::ot_Component: case UMLObject::ot_Port: case UMLObject::ot_Artifact: // trouble: artifact can also appear at Deployment mt = Uml::ModelType::Component; break; case UMLObject::ot_Node: mt = Uml::ModelType::Deployment; break; case UMLObject::ot_Entity: case UMLObject::ot_EntityAttribute: case UMLObject::ot_UniqueConstraint: case UMLObject::ot_ForeignKeyConstraint: case UMLObject::ot_CheckConstraint: case UMLObject::ot_Category: mt = Uml::ModelType::EntityRelationship; break; case UMLObject::ot_Association: { UMLAssociation *assoc = o->asUMLAssociation(); UMLDoc *umldoc = UMLApp::app()->document(); for (int r = Uml::RoleType::A; r <= Uml::RoleType::B; ++r) { UMLObject *roleObj = assoc->getObject(Uml::RoleType::fromInt(r)); if (roleObj == 0) { // Ouch! we have been called while types are not yet resolved return Uml::ModelType::N_MODELTYPES; } UMLPackage *pkg = roleObj->umlPackage(); if (pkg) { while (pkg->umlPackage()) { // wind back to root pkg = pkg->umlPackage(); } const Uml::ModelType::Enum m = umldoc->rootFolderType(pkg); if (m != Uml::ModelType::N_MODELTYPES) return m; } mt = guessContainer(roleObj); if (mt != Uml::ModelType::Logical) break; } } break; default: break; } return mt; } /** * Parse a direction string into the Uml::ParameterDirection::Enum. * * @param input The string to parse: "in", "out", or "inout" * optionally followed by whitespace. * @param result The corresponding Uml::ParameterDirection::Enum. * @return Length of the string matched, excluding the optional * whitespace. */ int stringToDirection(QString input, Uml::ParameterDirection::Enum & result) { QRegExp dirx(QLatin1String("^(in|out|inout)")); int pos = dirx.indexIn(input); if (pos == -1) return 0; const QString dirStr = dirx.capturedTexts().first(); int dirLen = dirStr.length(); if (input.length() > dirLen && !input[dirLen].isSpace()) return 0; // no match after all. if (dirStr == QLatin1String("out")) result = Uml::ParameterDirection::Out; else if (dirStr == QLatin1String("inout")) result = Uml::ParameterDirection::InOut; else result = Uml::ParameterDirection::In; return dirLen; } /** * Parses a template parameter given in UML syntax. * * @param t Input text of the template parameter. * Example: parname : partype * or just: parname (for class type) * @param nmTp NameAndType returned by this method. * @param owningScope Pointer to the owning scope of the template param. * @return Error status of the parse, PS_OK for success. */ Parse_Status parseTemplate(QString t, NameAndType& nmTp, UMLClassifier *owningScope) { UMLDoc *pDoc = UMLApp::app()->document(); t = t.trimmed(); if (t.isEmpty()) return PS_Empty; QStringList nameAndType = t.split(QRegExp(QLatin1String("\\s*:\\s*"))); if (nameAndType.count() == 2) { UMLObject *pType = 0; if (nameAndType[1] != QLatin1String("class")) { pType = pDoc->findUMLObject(nameAndType[1], UMLObject::ot_UMLObject, owningScope); if (pType == 0) return PS_Unknown_ArgType; } nmTp = NameAndType(nameAndType[0], pType); } else { nmTp = NameAndType(t, 0); } return PS_OK; } /** * Parses an attribute given in UML syntax. * * @param a Input text of the attribute in UML syntax. * Example: argname : argtype * @param nmTp NameAndType returned by this method. * @param owningScope Pointer to the owning scope of the attribute. * @param vis Optional pointer to visibility (return value.) * The visibility may be given at the beginning of the * attribute text in mnemonic form as follows: * "+" stands for public * "#" stands for protected * "-" stands for private * "~" stands for implementation level visibility * * @return Error status of the parse, PS_OK for success. */ Parse_Status parseAttribute(QString a, NameAndType& nmTp, UMLClassifier *owningScope, Uml::Visibility::Enum *vis /* = 0 */) { UMLDoc *pDoc = UMLApp::app()->document(); a = a.simplified(); if (a.isEmpty()) return PS_Empty; int colonPos = a.indexOf(QLatin1Char(':')); if (colonPos < 0) { nmTp = NameAndType(a, 0); return PS_OK; } QString name = a.left(colonPos).trimmed(); if (vis) { QRegExp mnemonicVis(QLatin1String("^([\\+\\#\\-\\~] *)")); int pos = mnemonicVis.indexIn(name); if (pos == -1) { *vis = Uml::Visibility::Private; // default value } else { QString caption = mnemonicVis.cap(1); QString strVis = caption.left(1); if (strVis == QLatin1String("+")) *vis = Uml::Visibility::Public; else if (strVis == QLatin1String("#")) *vis = Uml::Visibility::Protected; else if (strVis == QLatin1String("-")) *vis = Uml::Visibility::Private; else *vis = Uml::Visibility::Implementation; } name.remove(mnemonicVis); } Uml::ParameterDirection::Enum pd = Uml::ParameterDirection::In; if (name.startsWith(QLatin1String(QLatin1String("in ")))) { pd = Uml::ParameterDirection::In; name = name.mid(3); } else if (name.startsWith(QLatin1String(QLatin1String("inout ")))) { pd = Uml::ParameterDirection::InOut; name = name.mid(6); } else if (name.startsWith(QLatin1String(QLatin1String("out ")))) { pd = Uml::ParameterDirection::Out; name = name.mid(4); } a = a.mid(colonPos + 1).trimmed(); if (a.isEmpty()) { nmTp = NameAndType(name, 0, pd); return PS_OK; } QStringList typeAndInitialValue = a.split(QRegExp(QLatin1String("\\s*=\\s*"))); const QString &type = typeAndInitialValue[0]; UMLObject *pType = pDoc->findUMLObject(type, UMLObject::ot_UMLObject, owningScope); if (pType == 0) { nmTp = NameAndType(name, 0, pd); return PS_Unknown_ArgType; } QString initialValue; if (typeAndInitialValue.count() == 2) { initialValue = typeAndInitialValue[1]; } nmTp = NameAndType(name, pType, pd, initialValue); return PS_OK; } /** * Parses an operation given in UML syntax. * * @param m Input text of the operation in UML syntax. * Example of a two-argument operation returning "void": * methodname (arg1name : arg1type, arg2name : arg2type) : void * @param desc OpDescriptor returned by this method. * @param owningScope Pointer to the owning scope of the operation. * @return Error status of the parse, PS_OK for success. */ Parse_Status parseOperation(QString m, OpDescriptor& desc, UMLClassifier *owningScope) { UMLDoc *pDoc = UMLApp::app()->document(); m = m.simplified(); if (m.isEmpty()) return PS_Empty; if (m.contains(QRegExp(QLatin1String("operator *()")))) { // C++ special case: two sets of parentheses desc.m_name = QLatin1String("operator()"); m.remove(QRegExp(QLatin1String("operator *()"))); } else { /** * The search pattern includes everything up to the opening parenthesis * because UML also permits non programming-language oriented designs * using narrative names, for example "check water temperature". */ QRegExp beginningUpToOpenParenth(QLatin1String("^([^\\(]+)")); int pos = beginningUpToOpenParenth.indexIn(m); if (pos == -1) return PS_Illegal_MethodName; desc.m_name = beginningUpToOpenParenth.cap(1); } desc.m_pReturnType = 0; QRegExp pat = QRegExp(QLatin1String("\\) *:(.*)$")); int pos = pat.indexIn(m); if (pos != -1) { // return type is optional QString retType = pat.cap(1); retType = retType.trimmed(); if (retType != QLatin1String("void")) { UMLObject *pRetType = owningScope ? owningScope->findTemplate(retType) : 0; if (pRetType == 0) { pRetType = pDoc->findUMLObject(retType, UMLObject::ot_UMLObject, owningScope); if (pRetType == 0) return PS_Unknown_ReturnType; } desc.m_pReturnType = pRetType; } } // Remove possible empty parentheses () m.remove(QRegExp(QLatin1String("\\s*\\(\\s*\\)"))); desc.m_args.clear(); pat = QRegExp(QLatin1String("\\((.*)\\)")); pos = pat.indexIn(m); if (pos == -1) // argument list is optional return PS_OK; QString arglist = pat.cap(1); arglist = arglist.trimmed(); if (arglist.isEmpty()) return PS_OK; const QStringList args = arglist.split(QRegExp(QLatin1String("\\s*, \\s*"))); for (QStringList::ConstIterator lit = args.begin(); lit != args.end(); ++lit) { NameAndType nmTp; Parse_Status ps = parseAttribute(*lit, nmTp, owningScope); if (ps) return ps; desc.m_args.append(nmTp); } return PS_OK; } /** * Parses a constraint. * * @param m Input text of the constraint * * @param name The name returned by this method * @param owningScope Pointer to the owning scope of the constraint * @return Error status of the parse, PS_OK for success. */ Parse_Status parseConstraint(QString m, QString& name, UMLEntity* owningScope) { Q_UNUSED(owningScope); m = m.simplified(); if (m.isEmpty()) return PS_Empty; int colonPos = m.indexOf(QLatin1Char(':')); if (colonPos < 0) { name = m; return PS_OK; } name = m.left(colonPos).trimmed(); return PS_OK; } /** * Returns the Parse_Status as a text. */ QString psText(Parse_Status value) { const QString text[] = { i18n("OK"), i18nc("parse status", "Empty"), i18n("Malformed argument"), i18n("Unknown argument type"), i18n("Illegal method name"), i18n("Unknown return type"), i18n("Unspecified error") }; return text[(unsigned) value]; } /** * Return true if the listview type is one of the predefined root views * (root, logical, usecase, component, deployment, datatype, or entity- * relationship view.) */ bool typeIsRootView(UMLListViewItem::ListViewType type) { switch (type) { case UMLListViewItem::lvt_View: case UMLListViewItem::lvt_Logical_View: case UMLListViewItem::lvt_UseCase_View: case UMLListViewItem::lvt_Component_View: case UMLListViewItem::lvt_Deployment_View: case UMLListViewItem::lvt_EntityRelationship_Model: return true; break; default: break; } return false; } /** * Return true if the listview type also has a widget representation in diagrams. */ bool typeIsCanvasWidget(UMLListViewItem::ListViewType type) { switch (type) { case UMLListViewItem::lvt_Actor: case UMLListViewItem::lvt_UseCase: case UMLListViewItem::lvt_Class: case UMLListViewItem::lvt_Package: case UMLListViewItem::lvt_Logical_Folder: case UMLListViewItem::lvt_UseCase_Folder: case UMLListViewItem::lvt_Component_Folder: case UMLListViewItem::lvt_Deployment_Folder: case UMLListViewItem::lvt_EntityRelationship_Folder: case UMLListViewItem::lvt_Subsystem: case UMLListViewItem::lvt_Component: case UMLListViewItem::lvt_Port: case UMLListViewItem::lvt_Node: case UMLListViewItem::lvt_Artifact: case UMLListViewItem::lvt_Interface: case UMLListViewItem::lvt_Datatype: case UMLListViewItem::lvt_Enum: case UMLListViewItem::lvt_Entity: case UMLListViewItem::lvt_Category: return true; break; default: break; } return false; } /** * Return true if the listview type is a logical, usecase or component folder. */ bool typeIsFolder(UMLListViewItem::ListViewType type) { if (typeIsRootView(type) || type == UMLListViewItem::lvt_Datatype_Folder || type == UMLListViewItem::lvt_Logical_Folder || type == UMLListViewItem::lvt_UseCase_Folder || type == UMLListViewItem::lvt_Component_Folder || type == UMLListViewItem::lvt_Deployment_Folder || type == UMLListViewItem::lvt_EntityRelationship_Folder) { return true; } else { return false; } } /** * Return true if the listview type may act as a container for other objects, * i.e. if it is a folder, package, subsystem, or component. */ bool typeIsContainer(UMLListViewItem::ListViewType type) { if (typeIsFolder(type)) return true; return (type == UMLListViewItem::lvt_Package || type == UMLListViewItem::lvt_Subsystem || type == UMLListViewItem::lvt_Component || type == UMLListViewItem::lvt_Class || type == UMLListViewItem::lvt_Interface); } /** * Return true if the listview type is an attribute, operation, or template. */ bool typeIsClassifierList(UMLListViewItem::ListViewType type) { if (type == UMLListViewItem::lvt_Attribute || type == UMLListViewItem::lvt_Instance || type == UMLListViewItem::lvt_Operation || type == UMLListViewItem::lvt_Template || type == UMLListViewItem::lvt_EntityAttribute || type == UMLListViewItem::lvt_UniqueConstraint || type == UMLListViewItem::lvt_ForeignKeyConstraint || type == UMLListViewItem::lvt_PrimaryKeyConstraint || type == UMLListViewItem::lvt_CheckConstraint || type == UMLListViewItem::lvt_EnumLiteral || type == UMLListViewItem::lvt_InstanteAttribute) { return true; } else { return false; } } /** * Return true if the listview type is a classifier (Class, Entity, Enum) */ bool typeIsClassifier(UMLListViewItem::ListViewType type) { if (type == UMLListViewItem::lvt_Class || type == UMLListViewItem::lvt_Interface || type == UMLListViewItem::lvt_Entity || type == UMLListViewItem::lvt_Enum) { return true; } return false; } /** * Return true if the listview type is a settings entry. */ bool typeIsProperties(UMLListViewItem::ListViewType type) { switch (type) { case UMLListViewItem::lvt_Properties: case UMLListViewItem::lvt_Properties_AutoLayout: case UMLListViewItem::lvt_Properties_Class: case UMLListViewItem::lvt_Properties_CodeImport: case UMLListViewItem::lvt_Properties_CodeGeneration: case UMLListViewItem::lvt_Properties_CodeViewer: case UMLListViewItem::lvt_Properties_Font: case UMLListViewItem::lvt_Properties_General: case UMLListViewItem::lvt_Properties_UserInterface: return true; break; default: break; } return false; } /** * Check if a listviewitem of type childType is allowed * as child of type parentType */ bool typeIsAllowedInType(UMLListViewItem::ListViewType childType, UMLListViewItem::ListViewType parentType) { switch (childType) { case UMLListViewItem::lvt_Class: case UMLListViewItem::lvt_Package: case UMLListViewItem::lvt_Interface: case UMLListViewItem::lvt_Enum: case UMLListViewItem::lvt_Instance: return parentType == UMLListViewItem::lvt_Logical_View || parentType == UMLListViewItem::lvt_Class || parentType == UMLListViewItem::lvt_Package || parentType == UMLListViewItem::lvt_Logical_Folder; case UMLListViewItem::lvt_Attribute: case UMLListViewItem::lvt_EntityAttribute: case UMLListViewItem::lvt_InstanteAttribute: return parentType == UMLListViewItem::lvt_Entity; case UMLListViewItem::lvt_Operation: return parentType == UMLListViewItem::lvt_Class || parentType == UMLListViewItem::lvt_Interface; case UMLListViewItem::lvt_Datatype: return parentType == UMLListViewItem::lvt_Logical_Folder || parentType == UMLListViewItem::lvt_Datatype_Folder || parentType == UMLListViewItem::lvt_Class || parentType == UMLListViewItem::lvt_Interface || parentType == UMLListViewItem::lvt_Package; case UMLListViewItem::lvt_Class_Diagram: case UMLListViewItem::lvt_Collaboration_Diagram: case UMLListViewItem::lvt_State_Diagram: case UMLListViewItem::lvt_Activity_Diagram: case UMLListViewItem::lvt_Sequence_Diagram: case UMLListViewItem::lvt_Object_Diagram: return parentType == UMLListViewItem::lvt_Logical_Folder || parentType == UMLListViewItem::lvt_Logical_View; case UMLListViewItem::lvt_Logical_Folder: return parentType == UMLListViewItem::lvt_Logical_Folder || parentType == UMLListViewItem::lvt_Logical_View; case UMLListViewItem::lvt_UseCase_Folder: return parentType == UMLListViewItem::lvt_UseCase_Folder || parentType == UMLListViewItem::lvt_UseCase_View; case UMLListViewItem::lvt_Component_Folder: return parentType == UMLListViewItem::lvt_Component_Folder || parentType == UMLListViewItem::lvt_Component_View; case UMLListViewItem::lvt_Deployment_Folder: return parentType == UMLListViewItem::lvt_Deployment_Folder || parentType == UMLListViewItem::lvt_Deployment_View; case UMLListViewItem::lvt_EntityRelationship_Folder: return parentType == UMLListViewItem::lvt_EntityRelationship_Folder || parentType == UMLListViewItem::lvt_EntityRelationship_Model; case UMLListViewItem::lvt_Actor: case UMLListViewItem::lvt_UseCase: case UMLListViewItem::lvt_UseCase_Diagram: return parentType == UMLListViewItem::lvt_UseCase_Folder || parentType == UMLListViewItem::lvt_UseCase_View; case UMLListViewItem::lvt_Subsystem: return parentType == UMLListViewItem::lvt_Component_Folder || parentType == UMLListViewItem::lvt_Subsystem || parentType == UMLListViewItem::lvt_Component_View; case UMLListViewItem::lvt_Component: return parentType == UMLListViewItem::lvt_Component_Folder || parentType == UMLListViewItem::lvt_Component || parentType == UMLListViewItem::lvt_Subsystem || parentType == UMLListViewItem::lvt_Component_View; case UMLListViewItem::lvt_Port: return parentType == UMLListViewItem::lvt_Component || parentType == UMLListViewItem::lvt_Subsystem; case UMLListViewItem::lvt_Artifact: case UMLListViewItem::lvt_Component_Diagram: return parentType == UMLListViewItem::lvt_Component_Folder || parentType == UMLListViewItem::lvt_Component_View; case UMLListViewItem::lvt_Node: case UMLListViewItem::lvt_Deployment_Diagram: return parentType == UMLListViewItem::lvt_Deployment_Folder || parentType == UMLListViewItem::lvt_Deployment_View; case UMLListViewItem::lvt_Entity: case UMLListViewItem::lvt_EntityRelationship_Diagram: case UMLListViewItem::lvt_Category: return parentType == UMLListViewItem::lvt_EntityRelationship_Folder || parentType == UMLListViewItem::lvt_EntityRelationship_Model; default: return false; } } /** * Return true if the listview type is a diagram. */ bool typeIsDiagram(UMLListViewItem::ListViewType type) { if (type == UMLListViewItem::lvt_Class_Diagram || type == UMLListViewItem::lvt_Collaboration_Diagram || type == UMLListViewItem::lvt_State_Diagram || type == UMLListViewItem::lvt_Activity_Diagram || type == UMLListViewItem::lvt_Sequence_Diagram || type == UMLListViewItem::lvt_UseCase_Diagram || type == UMLListViewItem::lvt_Component_Diagram || type == UMLListViewItem::lvt_Deployment_Diagram || type == UMLListViewItem::lvt_EntityRelationship_Diagram || type == UMLListViewItem::lvt_Object_Diagram ){ return true; } else { return false; } } /** * Return the Model_Type which corresponds to the given DiagramType. */ Uml::ModelType::Enum convert_DT_MT(Uml::DiagramType::Enum dt) { Uml::ModelType::Enum mt; switch (dt) { case Uml::DiagramType::UseCase: mt = Uml::ModelType::UseCase; break; case Uml::DiagramType::Collaboration: case Uml::DiagramType::Class: case Uml::DiagramType::Object: case Uml::DiagramType::Sequence: case Uml::DiagramType::State: case Uml::DiagramType::Activity: mt = Uml::ModelType::Logical; break; case Uml::DiagramType::Component: mt = Uml::ModelType::Component; break; case Uml::DiagramType::Deployment: mt = Uml::ModelType::Deployment; break; case Uml::DiagramType::EntityRelationship: mt = Uml::ModelType::EntityRelationship; break; default: uError() << "Model_Utils::convert_DT_MT: illegal input value " << dt; mt = Uml::ModelType::N_MODELTYPES; break; } return mt; } /** * Return the ListViewType which corresponds to the given Model_Type. */ UMLListViewItem::ListViewType convert_MT_LVT(Uml::ModelType::Enum mt) { UMLListViewItem::ListViewType lvt = UMLListViewItem::lvt_Unknown; switch (mt) { case Uml::ModelType::Logical: lvt = UMLListViewItem::lvt_Logical_View; break; case Uml::ModelType::UseCase: lvt = UMLListViewItem::lvt_UseCase_View; break; case Uml::ModelType::Component: lvt = UMLListViewItem::lvt_Component_View; break; case Uml::ModelType::Deployment: lvt = UMLListViewItem::lvt_Deployment_View; break; case Uml::ModelType::EntityRelationship: lvt = UMLListViewItem::lvt_EntityRelationship_Model; break; default: break; } return lvt; } /** * Return the Model_Type which corresponds to the given ListViewType. * Returns Uml::N_MODELTYPES if the list view type given does not map * to a Model_Type. */ Uml::ModelType::Enum convert_LVT_MT(UMLListViewItem::ListViewType lvt) { Uml::ModelType::Enum mt = Uml::ModelType::N_MODELTYPES; switch (lvt) { case UMLListViewItem::lvt_Logical_View: mt = Uml::ModelType::Logical; break; case UMLListViewItem::lvt_UseCase_View: mt = Uml::ModelType::UseCase; break; case UMLListViewItem::lvt_Component_View: mt = Uml::ModelType::Component; break; case UMLListViewItem::lvt_Deployment_View: mt = Uml::ModelType::Deployment; break; case UMLListViewItem::lvt_EntityRelationship_Model: mt = Uml::ModelType::EntityRelationship; break; default: break; } return mt; } /** * Convert a diagram type enum to the equivalent list view type. */ UMLListViewItem::ListViewType convert_DT_LVT(Uml::DiagramType::Enum dt) { UMLListViewItem::ListViewType type = UMLListViewItem::lvt_Unknown; switch(dt) { case Uml::DiagramType::UseCase: type = UMLListViewItem::lvt_UseCase_Diagram; break; case Uml::DiagramType::Class: type = UMLListViewItem::lvt_Class_Diagram; break; case Uml::DiagramType::Object: type = UMLListViewItem::lvt_Object_Diagram; break; case Uml::DiagramType::Sequence: type = UMLListViewItem::lvt_Sequence_Diagram; break; case Uml::DiagramType::Collaboration: type = UMLListViewItem::lvt_Collaboration_Diagram; break; case Uml::DiagramType::State: type = UMLListViewItem::lvt_State_Diagram; break; case Uml::DiagramType::Activity: type = UMLListViewItem::lvt_Activity_Diagram; break; case Uml::DiagramType::Component: type = UMLListViewItem::lvt_Component_Diagram; break; case Uml::DiagramType::Deployment: type = UMLListViewItem::lvt_Deployment_Diagram; break; case Uml::DiagramType::EntityRelationship: type = UMLListViewItem::lvt_EntityRelationship_Diagram; break; default: uWarning() << "convert_DT_LVT() called on unknown diagram type"; } return type; } /** * Convert an object's type to the equivalent list view type * * @param o Pointer to the UMLObject whose type shall be converted * to the equivalent ListViewType. We cannot just * pass in a UMLObject::ObjectType because a UMLFolder is mapped * to different ListViewType values, depending on its * location in one of the predefined modelviews (Logical/ * UseCase/etc.) * @return The equivalent ListViewType. */ UMLListViewItem::ListViewType convert_OT_LVT(UMLObject *o) { UMLObject::ObjectType ot = o->baseType(); UMLListViewItem::ListViewType type = UMLListViewItem::lvt_Unknown; switch(ot) { case UMLObject::ot_UseCase: type = UMLListViewItem::lvt_UseCase; break; case UMLObject::ot_Actor: type = UMLListViewItem::lvt_Actor; break; case UMLObject::ot_Class: type = UMLListViewItem::lvt_Class; break; case UMLObject::ot_Package: if (o->stereotype() == QLatin1String("subsystem")) type = UMLListViewItem::lvt_Subsystem; else type = UMLListViewItem::lvt_Package; break; case UMLObject::ot_Folder: { UMLDoc *umldoc = UMLApp::app()->document(); UMLFolder *f = o->asUMLFolder(); do { const Uml::ModelType::Enum mt = umldoc->rootFolderType(f); if (mt != Uml::ModelType::N_MODELTYPES) { switch (mt) { case Uml::ModelType::Logical: type = UMLListViewItem::lvt_Logical_Folder; break; case Uml::ModelType::UseCase: type = UMLListViewItem::lvt_UseCase_Folder; break; case Uml::ModelType::Component: type = UMLListViewItem::lvt_Component_Folder; break; case Uml::ModelType::Deployment: type = UMLListViewItem::lvt_Deployment_Folder; break; case Uml::ModelType::EntityRelationship: type = UMLListViewItem::lvt_EntityRelationship_Folder; break; default: break; } return type; } } while ((f = f->umlPackage()->asUMLFolder()) != 0); uError() << "convert_OT_LVT(" << o->name() << "): internal error - object is not properly nested in folder"; } break; case UMLObject::ot_Component: type = UMLListViewItem::lvt_Component; break; case UMLObject::ot_Port: type = UMLListViewItem::lvt_Port; break; case UMLObject::ot_Node: type = UMLListViewItem::lvt_Node; break; case UMLObject::ot_Artifact: type = UMLListViewItem::lvt_Artifact; break; case UMLObject::ot_Interface: type = UMLListViewItem::lvt_Interface; break; case UMLObject::ot_Datatype: type = UMLListViewItem::lvt_Datatype; break; case UMLObject::ot_Enum: type = UMLListViewItem::lvt_Enum; break; case UMLObject::ot_EnumLiteral: type = UMLListViewItem::lvt_EnumLiteral; break; case UMLObject::ot_Entity: type = UMLListViewItem::lvt_Entity; break; case UMLObject::ot_Category: type = UMLListViewItem::lvt_Category; break; case UMLObject::ot_EntityAttribute: type = UMLListViewItem::lvt_EntityAttribute; break; case UMLObject::ot_UniqueConstraint: { UMLEntity* ent = o->umlParent()->asUMLEntity(); UMLUniqueConstraint* uc = o->asUMLUniqueConstraint(); if (ent->isPrimaryKey(uc)) { type = UMLListViewItem::lvt_PrimaryKeyConstraint; } else { type = UMLListViewItem::lvt_UniqueConstraint; } break; } case UMLObject::ot_ForeignKeyConstraint: type = UMLListViewItem::lvt_ForeignKeyConstraint; break; case UMLObject::ot_CheckConstraint: type = UMLListViewItem::lvt_CheckConstraint; break; case UMLObject::ot_Attribute: type = UMLListViewItem::lvt_Attribute; break; case UMLObject::ot_Operation: type = UMLListViewItem::lvt_Operation; break; case UMLObject::ot_Template: type = UMLListViewItem::lvt_Template; break; case UMLObject::ot_Association: type = UMLListViewItem::lvt_Association; break; case UMLObject::ot_Instance: type = UMLListViewItem::lvt_Instance; break; case UMLObject::ot_InstanceAttribute: type = UMLListViewItem::lvt_InstanteAttribute; break; default: break; } return type; } /** * Converts a list view type enum to the equivalent object type. * * @param lvt The ListViewType to convert. * @return The converted ObjectType if the listview type * has a UMLObject::ObjectType representation, else 0. */ UMLObject::ObjectType convert_LVT_OT(UMLListViewItem::ListViewType lvt) { UMLObject::ObjectType ot = (UMLObject::ObjectType)0; switch (lvt) { case UMLListViewItem::lvt_UseCase: ot = UMLObject::ot_UseCase; break; case UMLListViewItem::lvt_Actor: ot = UMLObject::ot_Actor; break; case UMLListViewItem::lvt_Class: ot = UMLObject::ot_Class; break; case UMLListViewItem::lvt_Package: case UMLListViewItem::lvt_Subsystem: ot = UMLObject::ot_Package; break; case UMLListViewItem::lvt_Component: ot = UMLObject::ot_Component; break; case UMLListViewItem::lvt_Port: ot = UMLObject::ot_Port; break; case UMLListViewItem::lvt_Node: ot = UMLObject::ot_Node; break; case UMLListViewItem::lvt_Artifact: ot = UMLObject::ot_Artifact; break; case UMLListViewItem::lvt_Interface: ot = UMLObject::ot_Interface; break; case UMLListViewItem::lvt_Datatype: ot = UMLObject::ot_Datatype; break; case UMLListViewItem::lvt_Enum: ot = UMLObject::ot_Enum; break; case UMLListViewItem::lvt_Entity: ot = UMLObject::ot_Entity; break; case UMLListViewItem::lvt_Category: ot = UMLObject::ot_Category; break; case UMLListViewItem::lvt_EntityAttribute: ot = UMLObject::ot_EntityAttribute; break; case UMLListViewItem::lvt_UniqueConstraint: ot = UMLObject::ot_UniqueConstraint; break; case UMLListViewItem::lvt_PrimaryKeyConstraint: ot = UMLObject::ot_UniqueConstraint; break; case UMLListViewItem::lvt_ForeignKeyConstraint: ot = UMLObject::ot_ForeignKeyConstraint; break; case UMLListViewItem::lvt_CheckConstraint: ot = UMLObject::ot_CheckConstraint; break; case UMLListViewItem::lvt_Attribute: ot = UMLObject::ot_Attribute; break; case UMLListViewItem::lvt_Operation: ot = UMLObject::ot_Operation; break; case UMLListViewItem::lvt_Template: ot = UMLObject::ot_Template; break; case UMLListViewItem::lvt_EnumLiteral: ot = UMLObject::ot_EnumLiteral; break; case UMLListViewItem::lvt_Instance: ot = UMLObject::ot_Instance; break; case UMLListViewItem::lvt_InstanteAttribute: ot = UMLObject::ot_InstanceAttribute; break; default: if (typeIsFolder(lvt)) ot = UMLObject::ot_Folder; break; } return ot; } /** * Return the IconType which corresponds to the given listview type. * * @param lvt ListViewType to convert. * @return The Icon_Utils::IconType corresponding to the lvt. * Returns it_Home in case no mapping to IconType exists. */ Icon_Utils::IconType convert_LVT_IT(UMLListViewItem::ListViewType lvt, UMLObject *o) { Icon_Utils::IconType icon = Icon_Utils::it_Home; switch (lvt) { case UMLListViewItem::lvt_UseCase_View: case UMLListViewItem::lvt_UseCase_Folder: icon = Icon_Utils::it_Folder_Grey; break; case UMLListViewItem::lvt_Logical_View: case UMLListViewItem::lvt_Logical_Folder: icon = Icon_Utils::it_Folder_Green; break; case UMLListViewItem::lvt_Datatype_Folder: icon = Icon_Utils::it_Folder_Orange; break; case UMLListViewItem::lvt_Component_View: case UMLListViewItem::lvt_Component_Folder: icon = Icon_Utils::it_Folder_Red; break; case UMLListViewItem::lvt_Deployment_View: case UMLListViewItem::lvt_Deployment_Folder: icon = Icon_Utils::it_Folder_Violet; break; case UMLListViewItem::lvt_EntityRelationship_Model: case UMLListViewItem::lvt_EntityRelationship_Folder: icon = Icon_Utils::it_Folder_Cyan; break; case UMLListViewItem::lvt_Actor: icon = Icon_Utils::it_Actor; break; case UMLListViewItem::lvt_Association: icon = Icon_Utils::it_Association; break; case UMLListViewItem::lvt_UseCase: icon = Icon_Utils::it_UseCase; break; case UMLListViewItem::lvt_Class: if (o && o->stereotype() == QLatin1String("class-or-package")) icon = Icon_Utils::it_ClassOrPackage; else icon = Icon_Utils::it_Class; break; case UMLListViewItem::lvt_Package: icon = Icon_Utils::it_Package; break; case UMLListViewItem::lvt_Subsystem: icon = Icon_Utils::it_Subsystem; break; case UMLListViewItem::lvt_Component: icon = Icon_Utils::it_Component; break; case UMLListViewItem::lvt_Port: icon = Icon_Utils::it_Port; break; case UMLListViewItem::lvt_Node: icon = Icon_Utils::it_Node; break; case UMLListViewItem::lvt_Artifact: icon = Icon_Utils::it_Artifact; break; case UMLListViewItem::lvt_Interface: icon = Icon_Utils::it_Interface; break; case UMLListViewItem::lvt_Datatype: icon = Icon_Utils::it_Datatype; break; case UMLListViewItem::lvt_Enum: icon = Icon_Utils::it_Enum; break; case UMLListViewItem::lvt_Entity: icon = Icon_Utils::it_Entity; break; case UMLListViewItem::lvt_Category: icon = Icon_Utils::it_Category; break; case UMLListViewItem::lvt_Template: icon = Icon_Utils::it_Template; break; case UMLListViewItem::lvt_Attribute: icon = Icon_Utils::it_Private_Attribute; break; case UMLListViewItem::lvt_EntityAttribute: icon = Icon_Utils::it_Private_Attribute; break; case UMLListViewItem::lvt_EnumLiteral: icon = Icon_Utils::it_Public_Attribute; break; case UMLListViewItem::lvt_Operation: icon = Icon_Utils::it_Public_Method; break; case UMLListViewItem::lvt_UniqueConstraint: icon = Icon_Utils::it_Unique_Constraint; break; case UMLListViewItem::lvt_PrimaryKeyConstraint: icon = Icon_Utils::it_PrimaryKey_Constraint; break; case UMLListViewItem::lvt_ForeignKeyConstraint: icon = Icon_Utils::it_ForeignKey_Constraint; break; case UMLListViewItem::lvt_CheckConstraint: icon = Icon_Utils::it_Check_Constraint; break; case UMLListViewItem::lvt_Class_Diagram: icon = Icon_Utils::it_Diagram_Class; break; case UMLListViewItem::lvt_Object_Diagram: icon = Icon_Utils::it_Diagram_Object; break; case UMLListViewItem::lvt_UseCase_Diagram: icon = Icon_Utils::it_Diagram_Usecase; break; case UMLListViewItem::lvt_Sequence_Diagram: icon = Icon_Utils::it_Diagram_Sequence; break; case UMLListViewItem::lvt_Collaboration_Diagram: icon = Icon_Utils::it_Diagram_Collaboration; break; case UMLListViewItem::lvt_State_Diagram: icon = Icon_Utils::it_Diagram_State; break; case UMLListViewItem::lvt_Activity_Diagram: icon = Icon_Utils::it_Diagram_Activity; break; case UMLListViewItem::lvt_Component_Diagram: icon = Icon_Utils::it_Diagram_Component; break; case UMLListViewItem::lvt_Deployment_Diagram: icon = Icon_Utils::it_Diagram_Deployment; break; case UMLListViewItem::lvt_EntityRelationship_Diagram: icon = Icon_Utils::it_Diagram_EntityRelationship; break; case UMLListViewItem::lvt_Properties: icon = Icon_Utils::it_Properties; break; case UMLListViewItem::lvt_Properties_AutoLayout: icon = Icon_Utils::it_Properties_AutoLayout; break; case UMLListViewItem::lvt_Properties_Class: icon = Icon_Utils::it_Properties_Class; break; case UMLListViewItem::lvt_Properties_CodeImport: icon = Icon_Utils::it_Properties_CodeImport; break; case UMLListViewItem::lvt_Properties_CodeGeneration: icon = Icon_Utils::it_Properties_CodeGeneration; break; case UMLListViewItem::lvt_Properties_CodeViewer: icon = Icon_Utils::it_Properties_CodeViewer; break; case UMLListViewItem::lvt_Properties_Font: icon = Icon_Utils::it_Properties_Font; break; case UMLListViewItem::lvt_Properties_General: icon = Icon_Utils::it_Properties_General; break; case UMLListViewItem::lvt_Properties_UserInterface: icon = Icon_Utils::it_Properties_UserInterface; break; case UMLListViewItem::lvt_Instance: icon = Icon_Utils::it_Instance; break; case UMLListViewItem::lvt_InstanteAttribute: icon = Icon_Utils::it_Private_Attribute; break; default: break; } return icon; } /** * Return the DiagramType which corresponds to the given listview type. * * @param lvt ListViewType to convert. * @return The Uml::DiagramType corresponding to the lvt. * Returns dt_Undefined in case no mapping to DiagramType exists. */ Uml::DiagramType::Enum convert_LVT_DT(UMLListViewItem::ListViewType lvt) { Uml::DiagramType::Enum dt = Uml::DiagramType::Undefined; switch (lvt) { case UMLListViewItem::lvt_Class_Diagram: dt = Uml::DiagramType::Class; break; case UMLListViewItem::lvt_UseCase_Diagram: dt = Uml::DiagramType::UseCase; break; case UMLListViewItem::lvt_Sequence_Diagram: dt = Uml::DiagramType::Sequence; break; case UMLListViewItem::lvt_Collaboration_Diagram: dt = Uml::DiagramType::Collaboration; break; case UMLListViewItem::lvt_State_Diagram: dt = Uml::DiagramType::State; break; case UMLListViewItem::lvt_Activity_Diagram: dt = Uml::DiagramType::Activity; break; case UMLListViewItem::lvt_Component_Diagram: dt = Uml::DiagramType::Component; break; case UMLListViewItem::lvt_Deployment_Diagram: dt = Uml::DiagramType::Deployment; break; case UMLListViewItem::lvt_EntityRelationship_Diagram: dt = Uml::DiagramType::EntityRelationship; break; case UMLListViewItem::lvt_Object_Diagram: dt = Uml::DiagramType::Object; break; default: break; } return dt; } /** * Converts a list view type enum to the equivalent settings dialog type. * * @param type The ListViewType to convert. * @return The converted settings dialog type */ MultiPageDialogBase::PageType convert_LVT_PT(UMLListViewItem::ListViewType type) { MultiPageDialogBase::PageType pt = MultiPageDialogBase::GeneralPage; switch (type) { case UMLListViewItem::lvt_Properties: pt = MultiPageDialogBase::GeneralPage; break; case UMLListViewItem::lvt_Properties_AutoLayout: pt = MultiPageDialogBase::AutoLayoutPage; break; case UMLListViewItem::lvt_Properties_Class: pt = MultiPageDialogBase::ClassPage; break; case UMLListViewItem::lvt_Properties_CodeImport: pt = MultiPageDialogBase::CodeImportPage; break; case UMLListViewItem::lvt_Properties_CodeGeneration: pt = MultiPageDialogBase::CodeGenerationPage; break; case UMLListViewItem::lvt_Properties_CodeViewer: pt = MultiPageDialogBase::CodeViewerPage; break; case UMLListViewItem::lvt_Properties_Font: pt = MultiPageDialogBase::FontPage; break; case UMLListViewItem::lvt_Properties_General: pt = MultiPageDialogBase::GeneralPage; break; case UMLListViewItem::lvt_Properties_UserInterface: pt = MultiPageDialogBase::UserInterfacePage; break; default: break; } return pt; } /** * Return the Model_Type which corresponds to the given ObjectType. */ Uml::ModelType::Enum convert_OT_MT(UMLObject::ObjectType ot) { Uml::ModelType::Enum mt = Uml::ModelType::N_MODELTYPES; switch (ot) { case UMLObject::ot_Actor: case UMLObject::ot_UseCase: mt = Uml::ModelType::UseCase; break; case UMLObject::ot_Component: case UMLObject::ot_Port: case UMLObject::ot_Artifact: mt = Uml::ModelType::Component; break; case UMLObject::ot_Node: mt = Uml::ModelType::Deployment; break; case UMLObject::ot_Entity: case UMLObject::ot_EntityAttribute: case UMLObject::ot_UniqueConstraint: case UMLObject::ot_ForeignKeyConstraint: case UMLObject::ot_CheckConstraint: case UMLObject::ot_Category: mt = Uml::ModelType::EntityRelationship; break; default: mt = Uml::ModelType::Logical; break; } return mt; } /** * Converts from the UpdateDeleteAction enum to a QString * @param uda The UpdateDeleteAction enum literal */ QString updateDeleteActionToString(UMLForeignKeyConstraint::UpdateDeleteAction uda) { switch(uda) { case UMLForeignKeyConstraint::uda_NoAction: return QLatin1String("NO ACTION"); case UMLForeignKeyConstraint::uda_Restrict: return QLatin1String("RESTRICT"); case UMLForeignKeyConstraint::uda_Cascade: return QLatin1String("CASCADE"); case UMLForeignKeyConstraint::uda_SetNull: return QLatin1String("SET NULL"); case UMLForeignKeyConstraint::uda_SetDefault: return QLatin1String("SET DEFAULT"); default: return QString(); } } /** * Return true if the object type is allowed in the related diagram * @param o UML object instance * @param scene diagram instance * @return true type is allowed * @return false type is not allowed */ bool typeIsAllowedInDiagram(UMLObject* o, UMLScene *scene) { //make sure dragging item onto correct diagram // concept - class, seq, coll diagram // actor, usecase - usecase diagram UMLObject::ObjectType ot = o->baseType(); Uml::ID::Type id = o->id(); Uml::DiagramType::Enum diagramType = scene->type(); bool bAccept = true; switch (diagramType) { case Uml::DiagramType::UseCase: if ((scene->widgetOnDiagram(id) && ot == UMLObject::ot_Actor) || (ot != UMLObject::ot_Actor && ot != UMLObject::ot_UseCase)) bAccept = false; break; case Uml::DiagramType::Class: if (scene->widgetOnDiagram(id) || (ot != UMLObject::ot_Class && ot != UMLObject::ot_Package && ot != UMLObject::ot_Interface && ot != UMLObject::ot_Enum && ot != UMLObject::ot_Datatype)) { bAccept = false; } break; case Uml::DiagramType::Object: if( scene->widgetOnDiagram(id) || (ot != UMLObject::ot_Instance)) bAccept = false; break; case Uml::DiagramType::Sequence: case Uml::DiagramType::Collaboration: if (ot != UMLObject::ot_Class && ot != UMLObject::ot_Interface && ot != UMLObject::ot_Actor) bAccept = false; break; case Uml::DiagramType::Deployment: if (scene->widgetOnDiagram(id)) bAccept = false; else if (ot != UMLObject::ot_Interface && ot != UMLObject::ot_Package && ot != UMLObject::ot_Component && ot != UMLObject::ot_Class && ot != UMLObject::ot_Node) bAccept = false; else if (ot == UMLObject::ot_Package && o->stereotype() != QLatin1String("subsystem")) bAccept = false; break; case Uml::DiagramType::Component: if (scene->widgetOnDiagram(id) || (ot != UMLObject::ot_Interface && ot != UMLObject::ot_Package && ot != UMLObject::ot_Component && ot != UMLObject::ot_Port && ot != UMLObject::ot_Artifact && ot != UMLObject::ot_Class)) bAccept = false; else if (ot == UMLObject::ot_Class && !o->isAbstract()) bAccept = false; else if (ot == UMLObject::ot_Port) { const bool componentOnDiagram = scene->widgetOnDiagram(o->umlPackage()->id()); bAccept = componentOnDiagram; } break; case Uml::DiagramType::EntityRelationship: if (scene->widgetOnDiagram(id) || (ot != UMLObject::ot_Entity && ot != UMLObject::ot_Category)) bAccept = false; break; default: break; } return bAccept; } /** * Return true if the widget type is allowed in the related diagram * @param w UML widget object * @param scene diagram instance * @return true type is allowed * @return false type is not allowed */ bool typeIsAllowedInDiagram(UMLWidget* w, UMLScene *scene) { UMLWidget::WidgetType wt = w->baseType(); Uml::DiagramType::Enum diagramType = scene->type(); bool bAccept = true; // TODO: check additional widgets switch (diagramType) { case Uml::DiagramType::Activity: case Uml::DiagramType::Class: case Uml::DiagramType::Object: case Uml::DiagramType::Collaboration: case Uml::DiagramType::Component: case Uml::DiagramType::Deployment: case Uml::DiagramType::EntityRelationship: case Uml::DiagramType::Sequence: case Uml::DiagramType::State: case Uml::DiagramType::UseCase: default: switch(wt) { case WidgetBase::wt_Note: break; case WidgetBase::wt_Text: { FloatingTextWidget *ft = w->asFloatingTextWidget(); if (ft && ft->textRole() != Uml::TextRole::Floating) { bAccept = false; } } break; default: bAccept = false; break; } break; } return bAccept; } /** * return true if given object type supports associatons * @param type uml object type to check */ bool hasAssociations(UMLObject::ObjectType type) { switch (type) { case UMLObject::ot_Actor: case UMLObject::ot_UseCase: case UMLObject::ot_Class: case UMLObject::ot_Package: case UMLObject::ot_Component: case UMLObject::ot_Node: case UMLObject::ot_Artifact: case UMLObject::ot_Interface: case UMLObject::ot_Enum: case UMLObject::ot_Entity: case UMLObject::ot_Datatype: case UMLObject::ot_Category: case UMLObject::ot_Instance: return true; default: return false; } } } // namespace Model_Utils diff --git a/umbrello/pics/global/CMakeLists.txt b/umbrello/pics/global/CMakeLists.txt index c6fa41db5..b45d8ebea 100644 --- a/umbrello/pics/global/CMakeLists.txt +++ b/umbrello/pics/global/CMakeLists.txt @@ -1,17 +1,13 @@ -if(NOT BUILD_KF5) - add_subdirectory(kde4) -else() - ecm_install_icons( - ICONS 16-apps-umbrello.png - 16-mimetypes-application-x-uml.png - 22-apps-umbrello.png - 32-apps-umbrello.png - 32-mimetypes-application-x-uml.png - 48-apps-umbrello.png - 64-apps-umbrello.png - 128-apps-umbrello.png - sc-apps-umbrello.svgz - THEME hicolor - DESTINATION ${ICON_INSTALL_DIR} - ) -endif() +ecm_install_icons( + ICONS 16-apps-umbrello.png + 16-mimetypes-application-x-uml.png + 22-apps-umbrello.png + 32-apps-umbrello.png + 32-mimetypes-application-x-uml.png + 48-apps-umbrello.png + 64-apps-umbrello.png + 128-apps-umbrello.png + sc-apps-umbrello.svgz + THEME hicolor + DESTINATION ${ICON_INSTALL_DIR} +) diff --git a/umbrello/pics/global/kde4/hi128-apps-umbrello.png b/umbrello/pics/global/hi128-apps-umbrello.png similarity index 100% rename from umbrello/pics/global/kde4/hi128-apps-umbrello.png rename to umbrello/pics/global/hi128-apps-umbrello.png diff --git a/umbrello/pics/global/kde4/hi16-apps-umbrello.png b/umbrello/pics/global/hi16-apps-umbrello.png similarity index 100% rename from umbrello/pics/global/kde4/hi16-apps-umbrello.png rename to umbrello/pics/global/hi16-apps-umbrello.png diff --git a/umbrello/pics/global/kde4/hi16-mimetypes-application-x-uml.png b/umbrello/pics/global/hi16-mimetypes-application-x-uml.png similarity index 100% rename from umbrello/pics/global/kde4/hi16-mimetypes-application-x-uml.png rename to umbrello/pics/global/hi16-mimetypes-application-x-uml.png diff --git a/umbrello/pics/global/kde4/hi22-apps-umbrello.png b/umbrello/pics/global/hi22-apps-umbrello.png similarity index 100% rename from umbrello/pics/global/kde4/hi22-apps-umbrello.png rename to umbrello/pics/global/hi22-apps-umbrello.png diff --git a/umbrello/pics/global/kde4/hi32-apps-umbrello.png b/umbrello/pics/global/hi32-apps-umbrello.png similarity index 100% rename from umbrello/pics/global/kde4/hi32-apps-umbrello.png rename to umbrello/pics/global/hi32-apps-umbrello.png diff --git a/umbrello/pics/global/kde4/hi32-mimetypes-application-x-uml.png b/umbrello/pics/global/hi32-mimetypes-application-x-uml.png similarity index 100% rename from umbrello/pics/global/kde4/hi32-mimetypes-application-x-uml.png rename to umbrello/pics/global/hi32-mimetypes-application-x-uml.png diff --git a/umbrello/pics/global/kde4/hi48-apps-umbrello.png b/umbrello/pics/global/hi48-apps-umbrello.png similarity index 100% rename from umbrello/pics/global/kde4/hi48-apps-umbrello.png rename to umbrello/pics/global/hi48-apps-umbrello.png diff --git a/umbrello/pics/global/kde4/hi64-apps-umbrello.png b/umbrello/pics/global/hi64-apps-umbrello.png similarity index 100% rename from umbrello/pics/global/kde4/hi64-apps-umbrello.png rename to umbrello/pics/global/hi64-apps-umbrello.png diff --git a/umbrello/pics/global/kde4/hisc-apps-umbrello.svgz b/umbrello/pics/global/hisc-apps-umbrello.svgz similarity index 100% rename from umbrello/pics/global/kde4/hisc-apps-umbrello.svgz rename to umbrello/pics/global/hisc-apps-umbrello.svgz diff --git a/umbrello/pics/global/kde4/CMakeLists.txt b/umbrello/pics/global/kde4/CMakeLists.txt deleted file mode 100644 index 83c413321..000000000 --- a/umbrello/pics/global/kde4/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -if(NOT BUILD_KF5) - kde4_install_icons(${ICON_INSTALL_DIR}) -endif() diff --git a/umbrello/umldoc.cpp b/umbrello/umldoc.cpp index 00aadbc2b..5abefe6ca 100644 --- a/umbrello/umldoc.cpp +++ b/umbrello/umldoc.cpp @@ -1,3509 +1,3509 @@ /*************************************************************************** * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * copyright (C) 2002-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "umldoc.h" // app includes #include "debug_utils.h" #include "uniqueid.h" #include "association.h" #include "package.h" #include "folder.h" #include "codegenerator.h" #include "classifier.h" #include "dialog_utils.h" #include "enum.h" #include "entity.h" #include "docwindow.h" #include "operation.h" #include "attribute.h" #include "template.h" #include "enumliteral.h" #include "stereotype.h" #include "classifierlistitem.h" #include "object_factory.h" #include "import_argo.h" #include "import_rose.h" #include "model_utils.h" #include "uml.h" #include "umllistview.h" #include "umllistviewitem.h" #include "umlview.h" #include "entityconstraint.h" #include "idchangelog.h" #include "umllistviewpopupmenu.h" #include "cmds.h" #include "diagramprintpage.h" #include "umlscene.h" #include "version.h" #include "worktoolbar.h" #include "models/diagramsmodel.h" #include "models/objectsmodel.h" #include "models/stereotypesmodel.h" // kde includes #include #if QT_VERSION < 0x050000 #include #endif #if QT_VERSION >= 0x050000 #include #endif #include #include #if QT_VERSION < 0x050000 #include #endif #include #if QT_VERSION < 0x050000 #include #include #include #endif // qt includes #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x050000 #include #endif #include #include #include #if QT_VERSION >= 0x050000 #include #include #endif #include #include DEBUG_REGISTER(UMLDoc) /** * Constructor for the fileclass of the application. */ UMLDoc::UMLDoc() : m_datatypeRoot(0), m_stereoList(UMLStereotypeList()), m_Name(i18n("UML Model")), m_modelID("m1"), m_count(0), m_modified(false), #if QT_VERSION >= 0x050000 m_doc_url(QUrl()), #else m_doc_url(KUrl()), #endif m_pChangeLog(0), m_bLoading(false), m_importing(false), m_Doc(QString()), m_pAutoSaveTimer(0), m_nViewID(Uml::ID::None), m_bTypesAreResolved(true), m_pCurrentRoot(0), m_bClosing(false), m_diagramsModel(new DiagramsModel), m_objectsModel(new ObjectsModel), m_stereotypesModel(new StereotypesModel(&m_stereoList)), m_resolution(0.0) { for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) m_root[i] = 0; } /** * Initialize the UMLDoc. * To be called after the constructor, before anything else. */ void UMLDoc::init() { // Initialize predefined folders. const char* nativeRootName[Uml::ModelType::N_MODELTYPES] = { "Logical View", "Use Case View", "Component View", "Deployment View", "Entity Relationship Model" }; const QString localizedRootName[Uml::ModelType::N_MODELTYPES] = { i18n("Logical View"), i18n("Use Case View"), i18n("Component View"), i18n("Deployment View"), i18n("Entity Relationship Model") }; for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { const QString rootName = QString::fromLatin1(nativeRootName[i]); QString id = rootName; id.replace(QLatin1Char(' '), QLatin1Char('_')); m_root[i] = new UMLFolder(rootName, Uml::ID::fromString(id)); m_root[i]->setLocalName(localizedRootName[i]); } createDatatypeFolder(); // Connect signals. UMLApp * pApp = UMLApp::app(); connect(this, SIGNAL(sigDiagramCreated(Uml::ID::Type)), pApp, SLOT(slotUpdateViews())); connect(this, SIGNAL(sigDiagramRemoved(Uml::ID::Type)), pApp, SLOT(slotUpdateViews())); connect(this, SIGNAL(sigDiagramRenamed(Uml::ID::Type)), pApp, SLOT(slotUpdateViews())); connect(this, SIGNAL(sigCurrentViewChanged()), pApp, SLOT(slotCurrentViewChanged())); } /** * Create the datatype folder and add it to the logical folder. */ void UMLDoc::createDatatypeFolder() { delete m_datatypeRoot; m_datatypeRoot = new UMLFolder(QLatin1String("Datatypes"), "Datatypes"); m_datatypeRoot->setLocalName(i18n("Datatypes")); m_datatypeRoot->setUMLPackage(m_root[Uml::ModelType::Logical]); Q_ASSERT(m_root[Uml::ModelType::Logical]); m_root[Uml::ModelType::Logical]->addObject(m_datatypeRoot); } /** * Destructor for the fileclass of the application. */ UMLDoc::~UMLDoc() { UMLApp * pApp = UMLApp::app(); disconnect(this, SIGNAL(sigDiagramCreated(Uml::ID::Type)), pApp, SLOT(slotUpdateViews())); disconnect(this, SIGNAL(sigDiagramRemoved(Uml::ID::Type)), pApp, SLOT(slotUpdateViews())); disconnect(this, SIGNAL(sigDiagramRenamed(Uml::ID::Type)), pApp, SLOT(slotUpdateViews())); disconnect(this, SIGNAL(sigCurrentViewChanged()), pApp, SLOT(slotCurrentViewChanged())); disconnect(m_pAutoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave())); delete m_pAutoSaveTimer; m_root[Uml::ModelType::Logical]->removeObject(m_datatypeRoot); delete m_datatypeRoot; for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { delete m_root[i]; } delete m_pChangeLog; qDeleteAll(m_stereoList); delete m_stereotypesModel; delete m_diagramsModel; delete m_objectsModel; } /** * Adds a view to the document which represents the document * contents. Usually this is your main view. * * @param view Pointer to the UMLView to add. */ void UMLDoc::addView(UMLView *view) { if (view == 0) { uError() << "argument is NULL"; return; } UMLFolder *f = view->umlScene()->folder(); if (f == 0) { uError() << "view folder is not set"; return; } DEBUG(DBG_SRC) << view->umlScene()->name() << " to folder " << *f << " (" << f->name() << ")"; f->addView(view); m_diagramsModel->addDiagram(view); UMLApp * pApp = UMLApp::app(); if (pApp->listView()) { connect(this, SIGNAL(sigObjectRemoved(UMLObject*)), view->umlScene(), SLOT(slotObjectRemoved(UMLObject*))); } if (!m_bLoading || pApp->currentView() == 0) { pApp->setCurrentView(view); } if (!m_bLoading) { view->show(); emit sigDiagramChanged(view->umlScene()->type()); } pApp->setDiagramMenuItemsState(true); pApp->slotUpdateViews(); } /** * Removes a view from the list of currently connected views. * * @param view Pointer to the UMLView to remove. * @param enforceCurrentView Switch to determine if we have a current view or not. * Most of the time, we DO want this, except when exiting the program. */ void UMLDoc::removeView(UMLView *view, bool enforceCurrentView) { if (!view) { uError() << "UMLDoc::removeView(UMLView *view) called with view = 0"; return; } DEBUG(DBG_SRC) << "<" << view->umlScene()->name() << ">"; if (UMLApp::app()->listView()) { disconnect(this, SIGNAL(sigObjectRemoved(UMLObject*)), view->umlScene(), SLOT(slotObjectRemoved(UMLObject*))); } view->hide(); UMLFolder *f = view->umlScene()->folder(); if (f == 0) { uError() << view->umlScene()->name() << ": view->getFolder() returns NULL"; return; } m_diagramsModel->removeDiagram(view); f->removeView(view); UMLView *currentView = UMLApp::app()->currentView(); if (currentView == view) { UMLApp::app()->setCurrentView(0); UMLViewList viewList; m_root[Uml::ModelType::Logical]->appendViews(viewList); UMLView* firstView = 0; if (!viewList.isEmpty()) { firstView = viewList.first(); } if (!firstView && enforceCurrentView) { //create a diagram QString name = createDiagramName(Uml::DiagramType::Class, false); createDiagram(m_root[Uml::ModelType::Logical], Uml::DiagramType::Class, name); qApp->processEvents(); m_root[Uml::ModelType::Logical]->appendViews(viewList); firstView = viewList.first(); } if (firstView) { changeCurrentView(firstView->umlScene()->ID()); UMLApp::app()->setDiagramMenuItemsState(true); } } delete view; } /** * Sets the URL of the document. * * @param url The KUrl to set. */ #if QT_VERSION >= 0x050000 void UMLDoc::setUrl(const QUrl &url) #else void UMLDoc::setUrl(const KUrl &url) #endif { m_doc_url = url; } /** * Returns the KUrl of the document. * * @return The KUrl of this UMLDoc. */ #if QT_VERSION >= 0x050000 const QUrl& UMLDoc::url() const #else const KUrl& UMLDoc::url() const #endif { return m_doc_url; } /** * Sets the URL of the document to "Untitled". */ void UMLDoc::setUrlUntitled() { #if QT_VERSION >= 0x050000 m_doc_url.setUrl(m_doc_url.toString(QUrl::RemoveFilename) + i18n("Untitled")); #else m_doc_url.setFileName(i18n("Untitled")); #endif } /** * "save modified" - Asks the user for saving if the document * is modified. * * @return True if document can be closed. */ bool UMLDoc::saveModified() { bool completed(true); if (!m_modified) { return completed; } UMLApp *win = UMLApp::app(); int want_save = KMessageBox::warningYesNoCancel(win, i18n("The current file has been modified.\nDo you want to save it?"), i18nc("warning message", "Warning"), KStandardGuiItem::save(), KStandardGuiItem::discard()); switch(want_save) { case KMessageBox::Yes: if (m_doc_url.fileName() == i18n("Untitled")) { if (win->slotFileSaveAs()) { closeDocument(); completed=true; } else { completed=false; } } else { saveDocument(url()); closeDocument(); completed=true; } break; case KMessageBox::No: setModified(false); closeDocument(); completed=true; break; case KMessageBox::Cancel: completed=false; break; default: completed=false; break; } return completed; } /** * Closes the current document. */ void UMLDoc::closeDocument() { m_bClosing = true; UMLApp::app()->setGenerator(Uml::ProgrammingLanguage::Reserved); // delete the codegen m_Doc = QString(); DocWindow* dw = UMLApp::app()->docWindow(); if (dw) { dw->reset(); } UMLApp::app()->logWindow()->clear(); UMLListView *listView = UMLApp::app()->listView(); if (listView) { listView->clean(); // store old setting - for restore of last setting bool m_bLoading_old = m_bLoading; m_bLoading = true; // This is to prevent document becoming modified. // For reference, here is an example of a call sequence that would // otherwise result in futile addToUndoStack() calls: // removeAllViews() => // UMLView::removeAllAssociations() => // UMLView::removeAssoc() => // UMLDoc::setModified(true, true) => // addToUndoStack(). removeAllViews(); m_bLoading = m_bLoading_old; // Remove all objects from the predefined folders. // @fixme With advanced code generation enabled, this crashes. removeAllObjects(); // Remove any stereotypes. if (stereotypes().count() > 0) { foreach(UMLStereotype *s, stereotypes()) { m_stereotypesModel->removeStereotype(s); delete s; } m_stereoList.clear(); } // Restore the datatype folder, it has been deleted above. createDatatypeFolder(); // this creates to much items only Logical View should be created listView->init(); } m_bClosing = false; } /** * Initializes the document generally. * * @return True if operation successful. */ bool UMLDoc::newDocument() { bool state = UMLApp::app()->document()->loading(); UMLApp::app()->document()->setLoading(true); closeDocument(); UMLApp::app()->setCurrentView(0); setUrlUntitled(); setResolution(qApp->desktop()->logicalDpiX()); //see if we need to start with a new diagram Settings::OptionState optionState = Settings::optionState(); Uml::DiagramType::Enum dt = optionState.generalState.diagram; Uml::ModelType::Enum mt = Model_Utils::convert_DT_MT(dt); if (mt == Uml::ModelType::N_MODELTYPES) { // don't allow no diagram dt = Uml::DiagramType::Class; mt = Uml::ModelType::Logical; } QString name = createDiagramName(dt, false); createDiagram(m_root[mt], dt, name); UMLApp::app()->initGenerator(); setModified(false); initSaveTimer(); UMLApp::app()->enableUndoAction(false); UMLApp::app()->clearUndoStack(); UMLApp::app()->document()->setLoading(state); return true; } /** * Loads the document by filename and format and emits the * updateViews() signal. * * @param url The filename in KUrl format. * @param format The format (optional.) * @return True if operation successful. */ #if QT_VERSION >= 0x050000 bool UMLDoc::openDocument(const QUrl& url, const char* format /* =0 */) #else bool UMLDoc::openDocument(const KUrl& url, const char* format /* =0 */) #endif { Q_UNUSED(format); if (url.fileName().length() == 0) { newDocument(); return false; } m_doc_url = url; closeDocument(); setResolution(0.0); // IMPORTANT: set m_bLoading to true // _AFTER_ the call of UMLDoc::closeDocument() // as it sets m_bLoading to false after it was temporarily // changed to true to block recording of changes in redo-buffer m_bLoading = true; #if QT_VERSION >= 0x050000 QTemporaryFile tmpfile; tmpfile.open(); QUrl dest(QUrl::fromLocalFile(tmpfile.fileName())); DEBUG(DBG_SRC) << "UMLDoc::openDocument: copy from " << url << " to " << dest << "."; KIO::FileCopyJob *job = KIO::file_copy(url, dest, -1, KIO::Overwrite); KJobWidgets::setWindow(job, UMLApp::app()); job->exec(); QFile file(tmpfile.fileName()); - if (job->error() || !tmpfile.exists()) { - if (!tmpfile.exists()) - DEBUG(DBG_SRC) << "UMLDoc::openDocument: temporary file <" << tmpfile.fileName() << "> failed!"; + if (job->error() || !file.exists()) { + if (!file.exists()) + DEBUG(DBG_SRC) << "UMLDoc::openDocument: temporary file <" << file.fileName() << "> failed!"; if (job->error()) DEBUG(DBG_SRC) << "UMLDoc::openDocument: " << job->errorString(); KMessageBox::error(0, i18n("The file <%1> does not exist.", url.toString()), i18n("Load Error")); setUrlUntitled(); m_bLoading = false; newDocument(); return false; } #else QString tmpfile; KIO::NetAccess::download(url, tmpfile, UMLApp::app()); QFile file(tmpfile); if (!file.exists()) { KMessageBox::error(0, i18n("The file %1 does not exist.", url.pathOrUrl()), i18n("Load Error")); setUrlUntitled(); m_bLoading = false; newDocument(); return false; } #endif // status of XMI loading bool status = false; // check if the xmi file is a compressed archive like tar.bzip2 or tar.gz QString filetype = m_doc_url.fileName(); QString mimetype; if (filetype.endsWith(QLatin1String(".tgz")) || filetype.endsWith(QLatin1String(".tar.gz"))) { mimetype = QLatin1String("application/x-gzip"); } else if (filetype.endsWith(QLatin1String(".tar.bz2"))) { mimetype = QLatin1String("application/x-bzip"); } if (mimetype.isEmpty() == false) { #if QT_VERSION >= 0x050000 - KTar archive(tmpfile.fileName(), mimetype); + KTar archive(file.fileName(), mimetype); #else KTar archive(tmpfile, mimetype); #endif if (archive.open(QIODevice::ReadOnly) == false) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("The file %1 seems to be corrupted.", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("The file %1 seems to be corrupted.", url.pathOrUrl()), i18n("Load Error")); KIO::NetAccess::removeTempFile(tmpfile); #endif setUrlUntitled(); m_bLoading = false; newDocument(); return false; } // get the root directory and all entries in const KArchiveDirectory * rootDir = archive.directory(); const QStringList entries = rootDir->entries(); QString entryMimeType; bool foundXMI = false; QStringList::ConstIterator it; QStringList::ConstIterator end(entries.end()); // now go through all entries till we find an xmi file for (it = entries.begin(); it != end; ++it) { // only check files, we do not go in subdirectories if (rootDir->entry(*it)->isFile() == true) { // we found a file, check the mimetype #if QT_VERSION >= 0x050000 QMimeDatabase db; entryMimeType = db.mimeTypeForFile(*it, QMimeDatabase::MatchExtension).name(); #else entryMimeType = KMimeType::findByPath(*it, 0, true)->name(); #endif if (entryMimeType == QLatin1String("application/x-uml")) { foundXMI = true; break; } } } // if we found an XMI file, we have to extract it to a temporary file if (foundXMI == true) { #if QT_VERSION >= 0x050000 QTemporaryDir tmp_dir; #else KTempDir tmp_dir; #endif KArchiveEntry * entry; KArchiveFile * fileEntry; // try to cast the file entry in the archive to an archive entry entry = const_cast(rootDir->entry(*it)); if (entry == 0) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.", url.pathOrUrl()), i18n("Load Error")); KIO::NetAccess::removeTempFile(tmpfile); #endif setUrlUntitled(); m_bLoading = false; newDocument(); return false; } // now try to cast the archive entry to a file entry, so that we can // extract the file fileEntry = dynamic_cast(entry); if (fileEntry == 0) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.", url.pathOrUrl()), i18n("Load Error")); KIO::NetAccess::removeTempFile(tmpfile); #endif setUrlUntitled(); m_bLoading = false; newDocument(); return false; } // now we can extract the file to the temporary directory #if QT_VERSION >= 0x050000 fileEntry->copyTo(tmp_dir.path() + QLatin1Char('/')); // now open the extracted file for reading QFile xmi_file(tmp_dir.path() + QLatin1Char('/') + *it); #else fileEntry->copyTo(tmp_dir.name()); // now open the extracted file for reading QFile xmi_file(tmp_dir.name() + *it); #endif if(!xmi_file.open(QIODevice::ReadOnly)) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem loading the extracted file: %1", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("There was a problem loading the extracted file: %1", url.pathOrUrl()), i18n("Load Error")); KIO::NetAccess::removeTempFile(tmpfile); #endif setUrlUntitled(); m_bLoading = false; newDocument(); return false; } m_bTypesAreResolved = false; status = loadFromXMI1(xmi_file, ENC_UNKNOWN); // close the extracted file and the temporary directory xmi_file.close(); } else { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("There was no XMI file found in the compressed file %1.", url.pathOrUrl()), i18n("Load Error")); KIO::NetAccess::removeTempFile(tmpfile); #endif setUrlUntitled(); m_bLoading = false; newDocument(); return false; } archive.close(); } else { // no, it seems to be an ordinary file if (!file.open(QIODevice::ReadOnly)) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem loading file: %1", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("There was a problem loading file: %1", url.pathOrUrl()), i18n("Load Error")); KIO::NetAccess::removeTempFile(tmpfile); #endif setUrlUntitled(); m_bLoading = false; newDocument(); return false; } if (filetype.endsWith(QLatin1String(".mdl"))) { setUrlUntitled(); m_bTypesAreResolved = false; status = Import_Rose::loadFromMDL(file); if (status) { if (UMLApp::app()->currentView() == 0) { QString name = createDiagramName(Uml::DiagramType::Class, false); createDiagram(m_root[Uml::ModelType::Logical], Uml::DiagramType::Class, name); setCurrentRoot(Uml::ModelType::Logical); } } } else if (filetype.endsWith(QLatin1String(".zargo"))) { setUrlUntitled(); status = Import_Argo::loadFromZArgoFile(file); } else { m_bTypesAreResolved = false; status = loadFromXMI1(file, ENC_UNKNOWN); } } if (file.isOpen()) file.close(); #if QT_VERSION < 0x050000 KIO::NetAccess::removeTempFile(tmpfile); #endif m_bLoading = false; m_bTypesAreResolved = true; if (!status) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem loading file: %1", url.toString()), i18n("Load Error")); #else KMessageBox::error(0, i18n("There was a problem loading file: %1", url.pathOrUrl()), i18n("Load Error")); #endif newDocument(); return false; } setModified(false); initSaveTimer(); UMLApp::app()->enableUndoAction(false); UMLApp::app()->clearUndoStack(); // for compatibility addDefaultStereotypes(); return true; } /** * Saves the document using the given filename and format. * * @param url The filename in KUrl format. * @param format The format (optional.) * @return True if operation successful. */ #if QT_VERSION >= 0x050000 bool UMLDoc::saveDocument(const QUrl& url, const char * format) #else bool UMLDoc::saveDocument(const KUrl& url, const char * format) #endif { Q_UNUSED(format); m_doc_url = url; bool uploaded = true; // first, we have to find out which format to use #if QT_VERSION >= 0x050000 QString strFileName = url.path(); #else QString strFileName = url.path(KUrl::RemoveTrailingSlash); #endif QFileInfo fileInfo(strFileName); QString fileExt = fileInfo.completeSuffix(); QString fileFormat = QLatin1String("xmi"); if (fileExt == QLatin1String("xmi") || fileExt == QLatin1String("bak.xmi")) { fileFormat = QLatin1String("xmi"); } else if (fileExt == QLatin1String("xmi.tgz") || fileExt == QLatin1String("bak.xmi.tgz")) { fileFormat = QLatin1String("tgz"); } else if (fileExt == QLatin1String("xmi.tar.bz2") || fileExt == QLatin1String("bak.xmi.tar.bz2")) { fileFormat = QLatin1String("bz2"); } else { fileFormat = QLatin1String("xmi"); } initSaveTimer(); if (fileFormat == QLatin1String("tgz") || fileFormat == QLatin1String("bz2")) { KTar * archive; #if QT_VERSION >= 0x050000 QTemporaryFile tmp_tgz_file; #else KTemporaryFile tmp_tgz_file; #endif tmp_tgz_file.setAutoRemove(false); tmp_tgz_file.open(); // first we have to check if we are saving to a local or remote file if (url.isLocalFile()) { if (fileFormat == QLatin1String("tgz")) { // check tgz or bzip archive = new KTar(url.toLocalFile(), QLatin1String("application/x-gzip")); } else { archive = new KTar(url.toLocalFile(), QLatin1String("application/x-bzip")); } } else { if (fileFormat == QLatin1String("tgz")) { // check tgz or bzip2 archive = new KTar(tmp_tgz_file.fileName(), QLatin1String("application/x-gzip")); } else { archive = new KTar(tmp_tgz_file.fileName(), QLatin1String("application/x-bzip")); } } // now check if we can write to the file if (archive->open(QIODevice::WriteOnly) == false) { uError() << "could not open" << archive->fileName(); #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem saving: %1", url.url(QUrl::PreferLocalFile)), i18n("Save Error")); #else KMessageBox::error(0, i18n("There was a problem saving file: %1", url.pathOrUrl()), i18n("Save Error")); #endif delete archive; return false; } // we have to create a temporary xmi file // we will add this file later to the archive #if QT_VERSION >= 0x050000 QTemporaryFile tmp_xmi_file; #else KTemporaryFile tmp_xmi_file; #endif tmp_xmi_file.setAutoRemove(false); if (!tmp_xmi_file.open()) { uError() << "could not open" << tmp_xmi_file.fileName(); #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem saving: %1", url.url(QUrl::PreferLocalFile)), i18n("Save Error")); #else KMessageBox::error(0, i18n("There was a problem saving file: %1", url.pathOrUrl()), i18n("Save Error")); #endif delete archive; return false; } saveToXMI1(tmp_xmi_file); // save XMI to this file... // now add this file to the archive, but without the extension QString tmpQString = url.fileName(); if (fileFormat == QLatin1String("tgz")) { tmpQString.remove(QRegExp(QLatin1String("\\.tgz$"))); } else { tmpQString.remove(QRegExp(QLatin1String("\\.tar\\.bz2$"))); } archive->addLocalFile(tmp_xmi_file.fileName(), tmpQString); if (!archive->close()) { uError() << "could not close" << archive->fileName(); #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem saving: %1", url.url(QUrl::PreferLocalFile)), i18n("Save Error")); #else KMessageBox::error(0, i18n("There was a problem saving file: %1", url.pathOrUrl()), i18n("Save Error")); #endif delete archive; return false; } // now the xmi file was added to the archive, so we can delete it tmp_xmi_file.setAutoRemove(true); // now we have to check, if we have to upload the file if (!url.isLocalFile()) { #if QT_VERSION >= 0x050000 KIO::FileCopyJob *job = KIO::file_copy(QUrl::fromLocalFile(tmp_tgz_file.fileName()), m_doc_url); KJobWidgets::setWindow(job, UMLApp::app()); job->exec(); uploaded = !job->error(); #else uploaded = KIO::NetAccess::upload(tmp_tgz_file.fileName(), m_doc_url, UMLApp::app()); #endif if (!uploaded) uError() << "could not upload file" << tmp_tgz_file.fileName() << "to" << url; } // now the archive was written to disk (or remote) so we can delete the // objects tmp_tgz_file.setAutoRemove(true); delete archive; } else { // save as normal uncompressed XMI #if QT_VERSION >= 0x050000 QTemporaryFile tmpfile; // we need this tmp file if we are writing to a remote file #else KTemporaryFile tmpfile; // we need this tmp file if we are writing to a remote file #endif tmpfile.setAutoRemove(false); // save in _any_ case to a temp file // -> if something goes wrong during saveToXMI1, the // original content is preserved // (e.g. if umbrello dies in the middle of the document model parsing // for saveToXMI1 due to some problems) /// @todo insert some checks in saveToXMI1 to detect a failed save attempt // lets open the file for writing if (!tmpfile.open()) { uError() << "could not open" << tmpfile.fileName(); #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem saving: %1", url.url(QUrl::PreferLocalFile)), i18n("Save Error")); #else KMessageBox::error(0, i18n("There was a problem saving file: %1", url.pathOrUrl()), i18n("Save Error")); #endif return false; } saveToXMI1(tmpfile); // save the xmi stuff to it // if it is a remote file, we have to upload the tmp file if (!url.isLocalFile()) { #if QT_VERSION >= 0x050000 KIO::FileCopyJob *job = KIO::file_copy(QUrl::fromLocalFile(tmpfile.fileName()), m_doc_url); KJobWidgets::setWindow(job, UMLApp::app()); job->exec(); uploaded = !job->error(); #else uploaded = KIO::NetAccess::upload(tmpfile.fileName(), m_doc_url, UMLApp::app()); #endif if (!uploaded) uError() << "could not upload file" << tmpfile.fileName() << "to" << url; } else { // now remove the original file #ifdef Q_OS_WIN tmpfile.setAutoRemove(true); #if QT_VERSION >= 0x050000 KIO::FileCopyJob* fcj = KIO::file_copy(QUrl::fromLocalFile(tmpfile.fileName()), url, -1, KIO::Overwrite); #else KIO::FileCopyJob* fcj = KIO::file_copy(tmpfile.fileName(), url, -1, KIO::Overwrite); #endif #else #if QT_VERSION >= 0x050000 KIO::FileCopyJob* fcj = KIO::file_move(QUrl::fromLocalFile(tmpfile.fileName()), url, -1, KIO::Overwrite); #else KIO::FileCopyJob* fcj = KIO::file_move(tmpfile.fileName(), url, -1, KIO::Overwrite); #endif #endif #if QT_VERSION >= 0x050000 KJobWidgets::setWindow(fcj, (QWidget*)UMLApp::app()); fcj->exec(); if (fcj->error()) { uError() << "Could not move" << tmpfile.fileName() << "to" << url; KMessageBox::error(0, i18n("There was a problem saving: %1", url.url(QUrl::PreferLocalFile)), i18n("Save Error")); #else if (KIO::NetAccess::synchronousRun(fcj, (QWidget*)UMLApp::app()) == false) { KMessageBox::error(0, i18n("There was a problem saving file: %1", url.pathOrUrl()), i18n("Save Error")); #endif setUrlUntitled(); return false; } } } if (!uploaded) { #if QT_VERSION >= 0x050000 KMessageBox::error(0, i18n("There was a problem uploading: %1", url.url(QUrl::PreferLocalFile)), i18n("Save Error")); #else KMessageBox::error(0, i18n("There was a problem uploading file: %1", url.pathOrUrl()), i18n("Save Error")); #endif setUrlUntitled(); } setModified(false); return uploaded; } /** * Sets up the signals needed by the program for it to work. */ void UMLDoc::setupSignals() { WorkToolBar *tb = UMLApp::app()->workToolBar(); connect(this, SIGNAL(sigDiagramChanged(Uml::DiagramType::Enum)), tb, SLOT(slotCheckToolBar(Uml::DiagramType::Enum))); } /** * Finds a view (diagram) by the ID given to method. * * @param id The ID of the view to search for. * @return Pointer to the view found, or NULL if not found. */ UMLView * UMLDoc::findView(Uml::ID::Type id) { UMLView *v = 0; for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { v = m_root[i]->findView(id); if (v) { break; } } return v; } /** * Finds a view (diagram) by the type and name given. * * @param type The type of view to find. * @param name The name of the view to find. * @param searchAllScopes Search in all subfolders (default: false.) * @return Pointer to the view found, or NULL if not found. */ UMLView * UMLDoc::findView(Uml::DiagramType::Enum type, const QString &name, bool searchAllScopes /* =false */) { Uml::ModelType::Enum mt = Model_Utils::convert_DT_MT(type); return m_root[mt]->findView(type, name, searchAllScopes); } /** * Used to find a reference to a @ref UMLObject by its ID. * * @param id The @ref UMLObject to find. * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* UMLDoc::findObjectById(Uml::ID::Type id) { UMLObject *o = 0; for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { if (id == m_root[i]->id()) { return m_root[i]; } o = m_root[i]->findObjectById(id); if (o) { return o; } } o = findStereotypeById(id); return o; } /** * Used to find a @ref UMLObject by its type and name. * * @param name The name of the @ref UMLObject to find. * @param type ObjectType of the object to find (optional.) * When the given type is ot_UMLObject the type is * disregarded, i.e. the given name is the only * search criterion. * @param currentObj Object relative to which to search (optional.) * If given then the enclosing scope(s) of this * object are searched before the global scope. * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* UMLDoc::findUMLObject(const QString &name, UMLObject::ObjectType type /* = ot_UMLObject */, UMLObject *currentObj /* = 0 */) { UMLObject *o = m_datatypeRoot->findObject(name); if (o) { return o; } for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { UMLObjectList &list = m_root[i]->containedObjects(); if (list.size() == 0) continue; o = Model_Utils::findUMLObject(list, name, type, currentObj); if (o) { return o; } if ((type == UMLObject::ot_UMLObject || type == UMLObject::ot_Folder) && name == m_root[i]->name()) { return m_root[i]; } } return 0; } /** * Used to find a @ref UMLObject by its type and raw name. * * @param modelType The model type in which to search for the object * @param name The raw name of the @ref UMLObject to find. * @param type ObjectType of the object to find * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* UMLDoc::findUMLObjectRaw(Uml::ModelType::Enum modelType, const QString &name, UMLObject::ObjectType type) { return findUMLObjectRaw(rootFolder(modelType), name, type); } /** * Used to find a @ref UMLObject by its type and raw name. * * @param folder The UMLFolder in which to search for the object * @param name The raw name of the @ref UMLObject to find. * @param type ObjectType of the object to find * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* UMLDoc::findUMLObjectRaw(UMLFolder *folder, const QString &name, UMLObject::ObjectType type) { if (folder == 0) return 0; UMLObjectList &list = folder->containedObjects(); if (list.size() == 0) return 0; return Model_Utils::findUMLObjectRaw(list, name, type, 0); } /** * Used to find a @ref UMLObject by its type and raw name recursivly * * @param modelType The model type in which to search for the object * @param name The raw name of the @ref UMLObject to find. * @param type ObjectType of the object to find * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* UMLDoc::findUMLObjectRecursive(Uml::ModelType::Enum modelType, const QString &name, UMLObject::ObjectType type) { return findUMLObjectRecursive(rootFolder(modelType), name, type); } /** * Used to find a @ref UMLObject by its type and raw name recursivly * * @param folder The UMLFolder in which to search for the object * @param name The raw name of the @ref UMLObject to find. * @param type ObjectType of the object to find * @return Pointer to the UMLObject found, or NULL if not found. */ UMLObject* UMLDoc::findUMLObjectRecursive(UMLFolder *folder, const QString &name, UMLObject::ObjectType type) { if (folder == 0) return 0; UMLObjectList &list = folder->containedObjects(); if (list.size() == 0) return 0; return Model_Utils::findUMLObjectRecursive(list, name, type); } /** * Used to find a @ref UMLClassifier by its name. * * @param name The name of the @ref UMLObject to find. */ UMLClassifier* UMLDoc::findUMLClassifier(const QString &name) { //this is used only by code generator so we don't need to look at Datatypes UMLObject * obj = findUMLObject(name); return obj->asUMLClassifier(); } /** * Adds a UMLObject thats already created but doesn't change * any ids or signal. Use AddUMLObjectPaste if pasting. * * @param object The object to add. * @return True if the object was actually added. */ bool UMLDoc::addUMLObject(UMLObject* object) { if (object->isUMLStereotype()) { DEBUG(DBG_SRC) << object->name() << ": not adding type " << object->baseTypeStr(); return false; } UMLPackage *pkg = object->umlPackage(); if (pkg == 0) { pkg = currentRoot(); DEBUG(DBG_SRC) << object->name() << ": no parent package set, assuming " << pkg->name(); object->setUMLPackage(pkg); } // FIXME restore stereotype UMLClassifierListItem *c = object->asUMLClassifierListItem(); if (c) { if (!pkg->subordinates().contains(c)) pkg->subordinates().append(c); return true; } return pkg->addObject(object); } /** * Write text to the status bar. * @param text the text to write */ void UMLDoc::writeToStatusBar(const QString &text) { emit sigWriteToStatusBar(text); } /** * Simple removal of an object. * @param object the UMLObject to be removed */ void UMLDoc::slotRemoveUMLObject(UMLObject* object) { //m_objectList.remove(object); UMLPackage *pkg = object->umlPackage(); if (pkg == 0) { uError() << object->name() << ": parent package is not set !"; return; } pkg->removeObject(object); } /** * Returns true if the given name is unique within its scope. * * @param name The name to check. * @return True if name is unique. */ bool UMLDoc::isUnique(const QString &name) { UMLListView *listView = UMLApp::app()->listView(); UMLListViewItem *currentItem = (UMLListViewItem*)listView->currentItem(); UMLListViewItem *parentItem = 0; // check for current item, if its a package, then we do a check on that // otherwise, if current item exists, find its parent and check if thats // a package.. if (currentItem) { // its possible that the current item *is* a package, then just // do check now if (Model_Utils::typeIsContainer(currentItem->type())) { return isUnique (name, (UMLPackage*) currentItem->umlObject()); } parentItem = (UMLListViewItem*)currentItem->parent(); } // item is in a package so do check only in that if (parentItem != 0 && Model_Utils::typeIsContainer(parentItem->type())) { UMLPackage *parentPkg = parentItem->umlObject()->asUMLPackage(); return isUnique(name, parentPkg); } uError() << name << ": Not currently in a package"; /* Check against all objects that _don't_ have a parent package. for (UMLObjectListIt oit(m_objectList); oit.current(); ++oit) { UMLObject *obj = oit.current(); if ((obj->getUMLPackage() == 0) && (obj->getName() == name)) return false; } */ return true; } /** * Returns true if the given name is unique within its scope of given package. * * @param name The name to check. * @param package The UMLPackage in which we have to determine the unique-ness * @return True if name is unique. */ bool UMLDoc::isUnique(const QString &name, UMLPackage *package) { // if a package, then only do check in that if (package) { return (package->findObject(name) == 0); } // Not currently in a package: ERROR uError() << name << " (2): Not currently in a package"; /* Check against all objects that _don't_ have a parent package. for (UMLObjectListIt oit(m_objectList); oit.current(); ++oit) { UMLObject *obj = oit.current(); if ((obj->getUMLPackage() == 0) && (obj->getName() == name)) return false; } */ return true; } /** * Creates a stereotype for the parent object. * @param name the name of the stereotype */ UMLStereotype* UMLDoc::createStereotype(const QString &name) { UMLStereotype *s = new UMLStereotype(name, Uml::ID::fromString(name)); addStereotype(s); return s; } /** * Finds a UMLStereotype by its name. * * @param name The name of the UMLStereotype to find. * @return Pointer to the UMLStereotype found, or NULL if not found. */ UMLStereotype* UMLDoc::findStereotype(const QString &name) { foreach (UMLStereotype *s, m_stereoList) { if (s->name() == name) { return s; } } return 0; } /** * Finds or creates a stereotype for the parent object. * @param name the name of the stereotype * @return the found stereotype object or a just created one */ UMLStereotype* UMLDoc::findOrCreateStereotype(const QString &name) { UMLStereotype *s = findStereotype(name); if (s != 0) { return s; } return createStereotype(name); } /** * Find a UMLStereotype by its unique ID. * @param id the unique ID * @return the found stereotype or NULL */ UMLStereotype * UMLDoc::findStereotypeById(Uml::ID::Type id) { foreach (UMLStereotype *s, m_stereoList) { if (s->id() == id) return s; } return 0; } /** * Add a UMLStereotype to the application. * @param s the stereotype to be added */ void UMLDoc::addStereotype(UMLStereotype *s) { if (m_stereotypesModel->addStereotype(s)) emit sigObjectCreated(s); } /** * Remove a UMLStereotype from the application. * @param s the stereotype to be removed */ void UMLDoc::removeStereotype(UMLStereotype *s) { if (m_stereotypesModel->removeStereotype(s)) emit sigObjectRemoved(s); } /** * Add a stereotype if it doesn't already exist. * Used by code generators, operations and attribute dialog. */ void UMLDoc::addDefaultStereotypes() { CodeGenerator *gen = UMLApp::app()->generator(); if (gen) { gen->createDefaultStereotypes(); } } /** * Returns a list of the stereotypes in this UMLDoc. * * @return List of UML stereotypes. */ const UMLStereotypeList& UMLDoc::stereotypes() const { return m_stereoList; } /** * Removes an association. * * @param assoc Pointer to the UMLAssociation to remove. * @param doSetModified Whether to mark the document as modified (default: true.) */ void UMLDoc::removeAssociation (UMLAssociation * assoc, bool doSetModified /*=true*/) { if (!assoc) { return; } // Remove the UMLAssociation from m_objectList. UMLPackage *pkg = assoc->umlPackage(); if (pkg == 0) { uError() << assoc->name() << ": parent package is not set !"; return; } pkg->removeObject(assoc); if (doSetModified) { // so we will save our document setModified(true); } } /** * Finds an association. * * @param assocType Type of the UMLAssociation to seek. * @param roleAObj Pointer to the role A UMLCanvasObject. * @param roleBObj Pointer to the role B UMLCanvasObject. * @param swap Optional pointer to boolean. * The bool is set to true if the association * matched with swapped roles, else it is set * to false. * @return Pointer to the UMLAssociation found or NULL if not found. */ UMLAssociation * UMLDoc::findAssociation(Uml::AssociationType::Enum assocType, const UMLObject *roleAObj, const UMLObject *roleBObj, bool *swap) { UMLAssociationList assocs = associations(); UMLAssociation *ret = 0; foreach (UMLAssociation* a, assocs) { if (a->getAssocType() != assocType) { continue; } if (a->getObject(Uml::RoleType::A) == roleAObj && a->getObject(Uml::RoleType::B) == roleBObj) { return a; } if (a->getObject(Uml::RoleType::A) == roleBObj && a->getObject(Uml::RoleType::B) == roleAObj) { ret = a; } } if (swap) { *swap = (ret != 0); } return ret; } /** * Creates AND adds an association between two UMLObjects. * Used by refactoring assistant. * NOTE: this method does not check if the association is valid / legal * * @param a The UMLObject "A" for the association (source) * @param b The UMLObject "B" for the association (destination) * @param type The association's type * @return The Association created */ UMLAssociation* UMLDoc::createUMLAssociation(UMLObject *a, UMLObject *b, Uml::AssociationType::Enum type) { bool swap; UMLAssociation *assoc = findAssociation(type, a, b, &swap); if (assoc == 0) { assoc = new UMLAssociation(type, a, b); assoc->setUMLPackage(a->umlPackage()); addAssociation(assoc); } return assoc; } /** * Adds an association. * * @param assoc Pointer to the UMLAssociation to add. */ void UMLDoc::addAssociation(UMLAssociation *assoc) { if (assoc == 0) { return; } // First, check that this association has not already been added. // This may happen when loading old XMI files where all the association // information was taken from the tag. UMLAssociationList assocs = associations(); foreach (UMLAssociation* a, assocs) { // check if its already been added (shouldn't be the case right now // as UMLAssociations only belong to one associationwidget at a time) if (a == assoc) { DEBUG(DBG_SRC) << "duplicate addition attempted"; return; } } // If we get here it's really a new association. // Add the UMLAssociation at the owning UMLPackage. UMLPackage *pkg = assoc->umlPackage(); if (pkg == 0) { uError() << assoc->name() << ": parent package is not set !"; return; } pkg->addObject(assoc); // I don't believe this appropriate, UMLAssociations ARENT UMLWidgets -b.t. // emit sigObjectCreated(o); setModified(true); } /** * Returns a name for the new object, appended with a number * if the default name is taken e.g. class diagram, class * diagram_1 etc. * @param type the diagram type * @return the unique view name */ QString UMLDoc::uniqueViewName(const Uml::DiagramType::Enum type) { QString dname; switch (type) { case Uml::DiagramType::UseCase: dname = i18n("use case diagram"); break; case Uml::DiagramType::Class: dname = i18n("class diagram"); break; case Uml::DiagramType::Sequence: dname = i18n("sequence diagram"); break; case Uml::DiagramType::Collaboration: dname = i18n("communication diagram"); break; case Uml::DiagramType::Object: dname = i18n("object diagram"); break; case Uml::DiagramType::State: dname = i18n("state diagram"); break; case Uml::DiagramType::Activity: dname = i18n("activity diagram"); break; case Uml::DiagramType::Component: dname = i18n("component diagram"); break; case Uml::DiagramType::Deployment: dname = i18n("deployment diagram"); break; case Uml::DiagramType::EntityRelationship: dname = i18n("entity relationship diagram"); break; default: uWarning() << "called with unknown diagram type"; break; } QString name = dname; for (int number = 1; findView(type, name, true); ++number) { name = dname + QLatin1Char('_') + QString::number(number); } return name; } /** * Returns true when loading a document file. * @return the value of the flag */ bool UMLDoc::loading() const { return m_bLoading || !m_bTypesAreResolved; } /** * Sets loading boolean flag to the value given. * @param state value to set */ void UMLDoc::setLoading(bool state /* = true */) { m_bLoading = state; } /** * Returns true when importing file(s). * @return the value of the flag */ bool UMLDoc::importing() const { return m_importing; } /** * Sets importing boolean flag to the value given. * @param state value to set */ void UMLDoc::setImporting(bool state /* = true */) { m_importing = state; } /** * Returns the m_bClosing flag. * @return the value of the flag */ bool UMLDoc::closing() const { return m_bClosing; } /** * Creates the name of the given diagram type. * @param type The type of diagram to create. * @param askForName If true shows a dialog box asking for name, * else uses a default name. * @return name of the new diagram */ QString UMLDoc::createDiagramName(Uml::DiagramType::Enum type, bool askForName /*= true */) { QString defaultName = uniqueViewName(type); QString name = defaultName; while (true) { if (askForName && !Dialog_Utils::askName(i18nc("diagram name", "Name"), i18n("Enter name:"), name)) break; if (name.length() == 0) { KMessageBox::error(0, i18n("That is an invalid name for a diagram."), i18n("Invalid Name")); } else if (findView(type, name)) { KMessageBox::error(0, i18n("A diagram is already using that name."), i18n("Not a Unique Name")); } else { return name; } } // end while return QString(); } /** * Creates a diagram of the given type. * * @param folder the folder in which tp create the diagram. * @param type the type of diagram to create * @param name the name for the diagram to create * @param id optional ID of new diagram * @return pointer to the UMLView of the new diagram */ UMLView* UMLDoc::createDiagram(UMLFolder *folder, Uml::DiagramType::Enum type, const QString& name, Uml::ID::Type id) { DEBUG(DBG_SRC) << "folder=" << folder->name() << " / type=" << Uml::DiagramType::toString(type) << " / name=" << name; if (id == Uml::ID::None) { id = UniqueID::gen(); } if (name.length() > 0) { UMLView* view = new UMLView(folder); view->umlScene()->setOptionState(Settings::optionState()); view->umlScene()->setName(name); view->umlScene()->setType(type); view->umlScene()->setID(id); addView(view); emit sigDiagramCreated(id); setModified(true); UMLApp::app()->enablePrint(true); changeCurrentView(id); return view; } return 0; } /** * Used to rename a document. This method takes care of everything. * You just need to give the ID of the diagram to the method. * * @param id The ID of the diagram to rename. */ void UMLDoc::renameDiagram(Uml::ID::Type id) { UMLView *view = findView(id); Uml::DiagramType::Enum type = view->umlScene()->type(); QString name = view->umlScene()->name(); while (true) { bool ok = Dialog_Utils::askName(i18nc("renaming diagram", "Name"), i18n("Enter name:"), name); if (!ok) { break; } if (name.length() == 0) { KMessageBox::error(0, i18n("That is an invalid name for a diagram."), i18n("Invalid Name")); } else if (!findView(type, name)) { view->umlScene()->setName(name); emit sigDiagramRenamed(id); setModified(true); break; } else { KMessageBox::error(0, i18n("A diagram is already using that name."), i18n("Not a Unique Name")); } } } /** * Used to rename a @ref UMLObject. The @ref UMLObject is to be an * actor, use case or concept. * * @param o The object to rename. */ void UMLDoc::renameUMLObject(UMLObject *o) { QString name = o->name(); while (true) { bool ok = Dialog_Utils::askName(i18nc("renaming uml object", "Name"), i18n("Enter name:"), name); if (!ok) { break; } if (name.length() == 0) { KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); } else if (isUnique(name)) { UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(o, name)); setModified(true); break; } else { KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); } } return; } /** * Used to rename an operation or attribute of a concept. * * @param o The attribute or operation to rename. */ void UMLDoc::renameChildUMLObject(UMLObject *o) { UMLClassifier* p = o->umlParent()->asUMLClassifier(); if (!p) { DEBUG(DBG_SRC) << "Cannot create object, no parent found."; return; } QString name = o->name(); while (true) { bool ok = Dialog_Utils::askName(i18nc("renaming child uml object", "Name"), i18n("Enter name:"), name); if (!ok) { break; } if (name.length() == 0) { KMessageBox::error(0, i18n("That is an invalid name."), i18n("Invalid Name")); } else if (p->findChildObject(name) == 0 || ((o->baseType() == UMLObject::ot_Operation) && KMessageBox::warningYesNo(0, i18n("The name you entered was not unique.\nIs this what you wanted?"), i18n("Name Not Unique"), KGuiItem(i18n("Use Name")), KGuiItem(i18n("Enter New Name"))) == KMessageBox::Yes)) { UMLApp::app()->executeCommand(new Uml::CmdRenameUMLObject(o, name)); setModified(true); break; } else { KMessageBox::error(0, i18n("That name is already being used."), i18n("Not a Unique Name")); } } } /** * Changes the current view (diagram) to the view with the given ID. * * @param id The ID of the view to change to. */ void UMLDoc::changeCurrentView(Uml::ID::Type id) { DEBUG(DBG_SRC) << "id=" << Uml::ID::toString(id); UMLView* view = findView(id); if (view) { UMLScene* scene = view->umlScene(); scene->setIsOpen(true); UMLApp::app()->setCurrentView(view); emit sigDiagramChanged(scene->type()); UMLApp::app()->setDiagramMenuItemsState(true); setModified(true); emit sigCurrentViewChanged(); // when clicking on a tab, the documentation of diagram is upated in docwindow UMLApp::app()->docWindow()->showDocumentation(scene); } else { uWarning() << "New current view was not found with id=" << Uml::ID::toString(id) << "!"; } } /** * Deletes a diagram from the current file. * * Undo command * * @param id The ID of the diagram to delete. */ void UMLDoc::removeDiagram(Uml::ID::Type id) { UMLView* umlView = findView(id); if (!umlView) { uError() << "Request to remove diagram " << Uml::ID::toString(id) << ": Diagram not found!"; return; } UMLScene* umlScene = umlView->umlScene(); if (Dialog_Utils::askDeleteDiagram(umlScene->name())) { UMLApp::app()->executeCommand(new Uml::CmdRemoveDiagram( umlScene->folder(), umlScene->type(), umlScene->name(), id )); } } /** * Deletes a diagram from the current file. * * @param id The ID of the diagram to delete. */ void UMLDoc::removeDiagramCmd(Uml::ID::Type id) { UMLApp::app()->docWindow()->updateDocumentation(true); UMLView* umlview = findView(id); if (!umlview) { uError() << "Request to remove diagram " << Uml::ID::toString(id) << ": Diagram not found!"; return; } removeView(umlview); emit sigDiagramRemoved(id); setModified(true); } /** * Return the currently selected root folder. * This will be an element from the m_root[] array. * @return the currently selected root folder or NULL */ UMLFolder *UMLDoc::currentRoot() { UMLView *currentView = UMLApp::app()->currentView(); if (currentView == 0) { if (m_pCurrentRoot) { return m_pCurrentRoot; } uError() << "m_pCurrentRoot is NULL"; return 0; } UMLFolder *f = currentView->umlScene()->folder(); while (f && f->umlPackage()) { f = f->umlParent()->asUMLFolder(); } return f; } /** * Set the current root folder. * * @param rootType The type of the root folder to set. * The element from m_root[] which is indexed * by this type is selected. */ void UMLDoc::setCurrentRoot(Uml::ModelType::Enum rootType) { m_pCurrentRoot = m_root[rootType]; } /** * Removes an @ref UMLObject from the current file. If this object * is being represented on a diagram it will also delete all those * representations. * * @param umlobject Pointer to the UMLObject to delete. * @param deleteObject Delete the UMLObject instance. */ void UMLDoc::removeUMLObject(UMLObject* umlobject, bool deleteObject) { if (umlobject == 0) { uError() << "called with NULL parameter"; return; } UMLApp::app()->docWindow()->updateDocumentation(true); UMLObject::ObjectType type = umlobject->baseType(); umlobject->setUMLStereotype(0); // triggers possible cleanup of UMLStereotype if (umlobject->asUMLClassifierListItem()) { UMLClassifier* parent = umlobject->umlParent()->asUMLClassifier(); if (parent == 0) { uError() << "parent of umlobject is NULL"; return; } if (type == UMLObject::ot_Operation) { parent->removeOperation(umlobject->asUMLOperation()); if (deleteObject) delete umlobject->asUMLOperation(); } else if (type == UMLObject::ot_EnumLiteral) { UMLEnum *e = parent->asUMLEnum(); e->removeEnumLiteral(umlobject->asUMLEnumLiteral()); } else if (type == UMLObject::ot_EntityAttribute) { UMLEntity *ent = parent->asUMLEntity(); ent->removeEntityAttribute(umlobject->asUMLClassifierListItem()); } else if (type == UMLObject::ot_UniqueConstraint || type == UMLObject::ot_ForeignKeyConstraint || type == UMLObject::ot_CheckConstraint) { UMLEntity* ent = parent->asUMLEntity(); ent->removeConstraint(umlobject->asUMLEntityConstraint()); } else { UMLClassifier* pClass = parent->asUMLClassifier(); if (pClass == 0) { uError() << "parent of umlobject has unexpected type " << parent->baseType(); return; } if (type == UMLObject::ot_Attribute) { pClass->removeAttribute(umlobject->asUMLAttribute()); } else if (type == UMLObject::ot_Template) { pClass->removeTemplate(umlobject->asUMLTemplate()); if (deleteObject) delete umlobject->asUMLTemplate(); } else { uError() << "umlobject has unexpected type " << type; } } } else { if (type == UMLObject::ot_Association) { UMLAssociation *a = umlobject->asUMLAssociation(); removeAssociation(a, false); // don't call setModified here, it's done below emit sigObjectRemoved(umlobject); if (deleteObject) delete a; } else { UMLPackage* pkg = umlobject->umlPackage(); if (pkg) { // Remove associations that this object may participate in. UMLCanvasObject *c = umlobject->asUMLCanvasObject(); if (c) { // In the current implementation, all associations live in the // root folder. UMLPackage* rootPkg = Model_Utils::rootPackage(c); if (rootPkg == 0) { uError() << umlobject->name() << ": root package is not set !"; return; } UMLObjectList &rootObjects = rootPkg->containedObjects(); // Store the associations to remove in a buffer because we // should not remove elements from m_objectList while it is // being iterated over. UMLAssociationList assocsToRemove; foreach (UMLObject *obj, rootObjects) { uIgnoreZeroPointer(obj); if (obj->baseType() == UMLObject::ot_Association) { UMLAssociation *assoc = obj->asUMLAssociation(); if (c->hasAssociation(assoc)) { assocsToRemove.append(assoc); } } } foreach (UMLAssociation *a, assocsToRemove) { removeAssociation(a, false); } } pkg->removeObject(umlobject); emit sigObjectRemoved(umlobject); if (deleteObject) delete umlobject; } else { uError() << umlobject->name() << ": parent package is not set !"; } } } setModified(true); } /** * Signal that a UMLObject has been created. * * @param o The object that has been created. */ void UMLDoc::signalUMLObjectCreated(UMLObject * o) { emit sigObjectCreated(o); /* This is the wrong place to do: setModified(true); Instead, that should be done by the callers when object creation and all its side effects (e.g. new widget in view, new list view item, etc.) is finalized. */ } /** * Set the name of this model. */ void UMLDoc::setName(const QString& name) { m_Name = name; } /** * Return the name of this model. */ QString UMLDoc::name() const { return m_Name; } /** * Set coordinates resolution for current document. * @param resolution document resolution in DPI */ void UMLDoc::setResolution(qreal resolution) { m_resolution = resolution; uDebug() << "screen dpi:" << qApp->desktop()->logicalDpiX() << "file dpi:" << resolution << "scale:" << qApp->desktop()->logicalDpiX() / resolution; } /** * Returns coordinates resolution for current document. * @return document resolution in DPI */ qreal UMLDoc::resolution() const { return m_resolution; } /** * Returns scale factor for recalculation of document coordinates. * @return scale factor */ qreal UMLDoc::dpiScale() const { #ifdef ENABLE_XMIRESOLUTION if (resolution() != 0.0) return (qreal)qApp->desktop()->logicalDpiX() / resolution(); else #endif return 1.0; } /** * Return the m_modelID (currently this a fixed value: * Umbrello supports only a single document.) */ Uml::ID::Type UMLDoc::modelID() const { return m_modelID; } /** * This method is called for saving the given model as a XMI file. * It is virtual and calls the corresponding saveToXMI1() functions * of the derived classes. * * @param file The file to be saved to. */ void UMLDoc::saveToXMI1(QIODevice& file) { QDomDocument doc; QDomProcessingInstruction xmlHeading = doc.createProcessingInstruction(QLatin1String("xml"), QString::fromLatin1("version=\"1.0\" encoding=\"UTF-8\"")); doc.appendChild(xmlHeading); QDomElement root = doc.createElement(QLatin1String("XMI")); root.setAttribute(QLatin1String("xmi.version"), QLatin1String("1.2")); QDateTime now = QDateTime::currentDateTime(); root.setAttribute(QLatin1String("timestamp"), now.toString(Qt::ISODate)); root.setAttribute(QLatin1String("verified"), QLatin1String("false")); root.setAttribute(QLatin1String("xmlns:UML"), QLatin1String("http://schema.omg.org/spec/UML/1.4")); doc.appendChild(root); QDomElement header = doc.createElement(QLatin1String("XMI.header")); QDomElement meta = doc.createElement(QLatin1String("XMI.metamodel")); meta.setAttribute(QLatin1String("xmi.name"), QLatin1String("UML")); meta.setAttribute(QLatin1String("xmi.version"), QLatin1String("1.4")); meta.setAttribute(QLatin1String("href"), QLatin1String("UML.xml")); header.appendChild(meta); /** * bugs.kde.org/56184 comment by M. Alanen 2004-12-19: * " XMI.model requires xmi.version. (or leave the whole XMI.model out, * it's not required) " QDomElement model = doc.createElement("XMI.model"); QFile* qfile = dynamic_cast(&file); if (qfile) { QString modelName = qfile->name(); modelName = modelName.section('/', -1); modelName = modelName.section('.', 0, 0); model.setAttribute("xmi.name", modelName); model.setAttribute("href", qfile->name()); } */ QDomElement documentation = doc.createElement(QLatin1String("XMI.documentation")); // If we consider it useful we might add user and contact details // QDomElement owner = doc.createElement("XMI.owner"); // owner.appendChild(doc.createTextNode("Jens Kruger")); // Add a User // documentation.appendChild(owner); // QDomElement contact = doc.createElement("XMI.contact"); // contact.appendChild(doc.createTextNode("je.krueger@web.de")); // add a contact // documentation.appendChild(contact); QDomElement exporter = doc.createElement(QLatin1String("XMI.exporter")); exporter.appendChild(doc.createTextNode(QLatin1String("umbrello uml modeller http://umbrello.kde.org"))); documentation.appendChild(exporter); QDomElement exporterVersion = doc.createElement(QLatin1String("XMI.exporterVersion")); exporterVersion.appendChild(doc.createTextNode(QLatin1String(XMI_FILE_VERSION))); documentation.appendChild(exporterVersion); // all files are now saved with correct Unicode encoding, we add this // information to the header, so that the file will be loaded correctly QDomElement exporterEncoding = doc.createElement(QLatin1String("XMI.exporterEncoding")); exporterEncoding.appendChild(doc.createTextNode(QLatin1String("UnicodeUTF8"))); documentation.appendChild(exporterEncoding); header.appendChild(documentation); // See comment on above // header.appendChild(model); header.appendChild(meta); root.appendChild(header); QDomElement content = doc.createElement(QLatin1String("XMI.content")); QDomElement contentNS = doc.createElement(QLatin1String("UML:Namespace.contents")); QDomElement objectsElement = doc.createElement(QLatin1String("UML:Model")); objectsElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_modelID)); objectsElement.setAttribute(QLatin1String("name"), m_Name); objectsElement.setAttribute(QLatin1String("isSpecification"), QLatin1String("false")); objectsElement.setAttribute(QLatin1String("isAbstract"), QLatin1String("false")); objectsElement.setAttribute(QLatin1String("isRoot"), QLatin1String("false")); objectsElement.setAttribute(QLatin1String("isLeaf"), QLatin1String("false")); QDomElement ownedNS = doc.createElement(QLatin1String("UML:Namespace.ownedElement")); // Save stereotypes and toplevel datatypes first so that upon loading // they are known first. // There is a bug causing duplication of the same stereotype in m_stereoList. // As a workaround, we use a string list to memorize which stereotype has been saved. QStringList stereoNames; foreach (UMLStereotype *s, m_stereoList) { QString stName = s->name(); if (!stereoNames.contains(stName)) { s->saveToXMI1(doc, ownedNS); stereoNames.append(stName); } } for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { m_root[i]->saveToXMI1(doc, ownedNS); } objectsElement.appendChild(ownedNS); content.appendChild(objectsElement); root.appendChild(content); // Save the XMI extensions: docsettings, diagrams, listview, and codegeneration. QDomElement extensions = doc.createElement(QLatin1String("XMI.extensions")); extensions.setAttribute(QLatin1String("xmi.extender"), QLatin1String("umbrello")); QDomElement docElement = doc.createElement(QLatin1String("docsettings")); Uml::ID::Type viewID = Uml::ID::None; UMLView *currentView = UMLApp::app()->currentView(); if (currentView) { viewID = currentView->umlScene()->ID(); } docElement.setAttribute(QLatin1String("viewid"), Uml::ID::toString(viewID)); docElement.setAttribute(QLatin1String("documentation"), m_Doc); docElement.setAttribute(QLatin1String("uniqueid"), Uml::ID::toString(UniqueID::get())); extensions.appendChild(docElement); // save listview UMLApp::app()->listView()->saveToXMI1(doc, extensions); // save code generator CodeGenerator *codegen = UMLApp::app()->generator(); if (codegen) { QDomElement codeGenElement = doc.createElement(QLatin1String("codegeneration")); codegen->saveToXMI1(doc, codeGenElement); extensions.appendChild(codeGenElement); } root.appendChild(extensions); QTextStream stream(&file); stream.setCodec("UTF-8"); stream << doc.toString(); } /** * Checks the given XMI file if it was saved with correct Unicode * encoding set or not. * * @param file The file to be checked. */ short UMLDoc::encoding(QIODevice & file) { QTextStream stream(&file); stream.setCodec("UTF-8"); QString data = stream.readAll(); QString error; int line; QDomDocument doc; if (!doc.setContent(data, false, &error, &line)) { uWarning() << "Cannot set content: " << error << " Line: " << line; return ENC_UNKNOWN; } // we start at the beginning and go to the point in the header where we can // find out if the file was saved using Unicode QDomNode node = doc.firstChild(); short enc = ENC_UNKNOWN; while (node.isComment() || node.isProcessingInstruction()) { if (node.isProcessingInstruction()) { const QDomProcessingInstruction& pi = node.toProcessingInstruction(); QRegExp rx(QLatin1String("\\bencoding=['\"]([^'\"]+)['\"]")); const int pos = rx.indexIn(pi.data()); if (pos >= 0) { const QString& encData = rx.cap(1); if (encData == QLatin1String("UTF-8")) { enc = ENC_UNICODE; } else if (encData == QLatin1String("windows-1252")) { enc = ENC_WINDOWS; } else { uDebug() << "ProcessingInstruction encoding=" << encData << " is not yet implemented"; enc = ENC_OLD_ENC; } } } node = node.nextSibling(); } QDomElement root = node.toElement(); if (root.isNull()) { uDebug() << "Null element at " << node.nodeName() << " : " << node.nodeValue(); return enc; } // make sure it is an XMI file if (root.tagName() != QLatin1String("XMI") && root.tagName() != QLatin1String("xmi:XMI")) { uDebug() << "Unknown tag at " << root.tagName(); return enc; } if (node.firstChild().isNull()) { uDebug() << "No child at " << node.nodeName() << " : " << node.nodeValue(); return enc; } node = node.firstChild(); QDomElement element = node.toElement(); // check header if (element.isNull()) { uDebug() << "No element at " << node.nodeName() << " : " << node.nodeValue(); return enc; } if (element.tagName() != QLatin1String("XMI.header")) { uDebug() << "Expecting XMI.header at " << element.tagName(); return enc; } QDomNode headerNode = node.firstChild(); while (!headerNode.isNull()) { QDomElement headerElement = headerNode.toElement(); // the information if Unicode was used is now stored in the // XMI.documentation section of the header if (headerElement.isNull() || headerElement.tagName() != QLatin1String("XMI.documentation")) { headerNode = headerNode.nextSibling(); continue; } QDomNode docuNode = headerNode.firstChild(); while (!docuNode.isNull()) { QDomElement docuElement = docuNode.toElement(); // a tag XMI.exporterEncoding was added since version 1.2 to // mark a file as saved with Unicode if (! docuElement.isNull() && docuElement.tagName() == QLatin1String("XMI.exporterEncoding")) { // at the moment this isn't really necessary but maybe // later we will have other encoding standards if (docuElement.text() == QLatin1String("UnicodeUTF8")) { return ENC_UNICODE; // stop here } } docuNode = docuNode.nextSibling(); } break; } return ENC_OLD_ENC; } /** * Load a given XMI model from a file. If the encoding of the file * is already known it can be passed to the function. If this info * isn't given, loadFromXMI1 will check which encoding was used. * * @param file The file to be loaded. * @param encode The encoding used. */ bool UMLDoc::loadFromXMI1(QIODevice & file, short encode) { // old Umbrello versions (version < 1.2) didn't save the XMI in Unicode // this wasn't correct, because non Latin1 chars where lost // to ensure backward compatibility we have to ensure to load the old files // with non Unicode encoding if (encode == ENC_UNKNOWN) { if ((encode = encoding(file)) == ENC_UNKNOWN) { return false; } file.reset(); } QTextStream stream(&file); if (encode == ENC_UNICODE) { stream.setCodec("UTF-8"); } else if (encode == ENC_WINDOWS) { stream.setCodec("windows-1252"); } QString data = stream.readAll(); qApp->processEvents(); // give UI events a chance QString error; int line; QDomDocument doc; if (!doc.setContent(data, false, &error, &line)) { uWarning() << "Cannot set content:" << error << " Line:" << line; return false; } qApp->processEvents(); // give UI events a chance QDomNode node = doc.firstChild(); //Before Umbrello 1.1-rc1 we didn't add a listView(); lv->setTitle(0, m_Name); recognized = true; } if (outerTag != QLatin1String("XMI.content")) { if (!recognized) { DEBUG(DBG_SRC) << "skipping <" << outerTag << ">"; } continue; } bool seen_UMLObjects = false; //process content for (QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling()) { if (child.isComment()) { continue; } element = child.toElement(); QString tag = element.tagName(); if (tag == QLatin1String("umlobjects") // for bkwd compat. || tagEq(tag, QLatin1String("Subsystem")) || tagEq(tag, QLatin1String("Project")) // Embarcadero's Describe || tagEq(tag, QLatin1String("Model"))) { if(!loadUMLObjectsFromXMI1(element)) { uWarning() << "failed load on objects"; return false; } m_Name = element.attribute(QLatin1String("name"), i18n("UML Model")); UMLListView *lv = UMLApp::app()->listView(); lv->setTitle(0, m_Name); seen_UMLObjects = true; } else if (tagEq(tag, QLatin1String("Package")) || tagEq(tag, QLatin1String("Class")) || tagEq(tag, QLatin1String("Interface"))) { // These tests are only for foreign XMI files that // are missing the tag (e.g. NSUML) QString stID = element.attribute(QLatin1String("stereotype")); UMLObject *pObject = Object_Factory::makeObjectFromXMI(tag, stID); if (!pObject) { uWarning() << "Unknown type of umlobject to create: " << tag; // We want a best effort, therefore this is handled as a // soft error. continue; } UMLObject::ObjectType ot = pObject->baseType(); // Set the parent root folder. UMLPackage *pkg = 0; if (ot != UMLObject::ot_Stereotype) { if (ot == UMLObject::ot_Datatype) { pkg = m_datatypeRoot; } else { Uml::ModelType::Enum guess = Model_Utils::guessContainer(pObject); if (guess != Uml::ModelType::N_MODELTYPES) { pkg = m_root[guess]; } else { uError() << "Guess is Uml::ModelType::N_MODELTYPES - package not set correctly for " << pObject->name() << " / base type " << pObject->baseTypeStr(); pkg = m_root[Uml::ModelType::Logical]; } } } pObject->setUMLPackage(pkg); bool status = pObject->loadFromXMI1(element); if (!status) { delete pObject; return false; } seen_UMLObjects = true; } else if (tagEq(tag, QLatin1String("TaggedValue"))) { // This tag is produced here, i.e. outside of , // by the Unisys.JCR.1 Rose-to-XMI tool. if (! seen_UMLObjects) { DEBUG(DBG_SRC) << "skipping TaggedValue because not seen_UMLObjects"; continue; } tag = element.attribute(QLatin1String("tag")); if (tag != QLatin1String("documentation")) { continue; } QString modelElement = element.attribute(QLatin1String("modelElement")); if (modelElement.isEmpty()) { DEBUG(DBG_SRC) << "skipping TaggedValue(documentation) because " << "modelElement.isEmpty()"; continue; } UMLObject *o = findObjectById(Uml::ID::fromString(modelElement)); if (o == 0) { DEBUG(DBG_SRC) << "TaggedValue(documentation): cannot find object" << " for modelElement " << modelElement; continue; } QString value = element.attribute(QLatin1String("value")); if (! value.isEmpty()) { o->setDoc(value); } } else { // for backward compatibility loadExtensionsFromXMI1(child); } } } resolveTypes(); loadDiagrams1(); // set a default code generator if no tag seen if (UMLApp::app()->generator() == 0) { UMLApp::app()->setGenerator(UMLApp::app()->defaultLanguage()); } emit sigWriteToStatusBar(i18n("Setting up the document...")); qApp->processEvents(); // give UI events a chance activateAllViews(); UMLView *viewToBeSet = 0; if (m_nViewID != Uml::ID::None) { viewToBeSet = findView(m_nViewID); } if (viewToBeSet) { changeCurrentView(m_nViewID); } else { QString name = createDiagramName(Uml::DiagramType::Class, false); createDiagram(m_root[Uml::ModelType::Logical], Uml::DiagramType::Class, name); m_pCurrentRoot = m_root[Uml::ModelType::Logical]; } emit sigResetStatusbarProgress(); return true; } /** * Type resolution pass. */ void UMLDoc::resolveTypes() { // Resolve the types. // This is done in a separate pass because of possible forward references. if (m_bTypesAreResolved) { return; } writeToStatusBar(i18n("Resolving object references...")); for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { UMLFolder *obj = m_root[i]; #ifdef VERBOSE_DEBUGGING DEBUG(DBG_SRC) << "UMLDoc: invoking resolveRef() for " << obj->name() << " (id=" << Uml::ID::toString(obj->id()) << ")"; #endif obj->resolveRef(); } m_bTypesAreResolved = true; qApp->processEvents(); // give UI events a chance } /** * Load all diagrams collected from the xmi file. * * Loading diagrams is implemented as additional pass to avoid unresolved * uml objects which are defined later in the xmi file. */ bool UMLDoc::loadDiagrams1() { bool result = true; DiagramsMap::const_iterator i; for (i = m_diagramsToLoad.constBegin(); i != m_diagramsToLoad.constEnd(); i++) { UMLFolder *f = i.key(); foreach(QDomNode node, i.value()) if (!f->loadDiagramsFromXMI1(node)) result = false; } m_diagramsToLoad.clear(); return result; } /** * Add a xml node containing a diagram to the list of diagrams to load. * Helper function for loadDiagrams(). * * @param folder pointer to UMFolder instance the diagrams belongs to * @param node xml document node containing the diagram */ void UMLDoc::addDiagramToLoad(UMLFolder *folder, QDomNode node) { if (m_diagramsToLoad.contains(folder)) m_diagramsToLoad[folder].append(node); else m_diagramsToLoad[folder] = QList() << node; } DiagramsModel *UMLDoc::diagramsModel() { return m_diagramsModel; } ObjectsModel *UMLDoc::objectsModel() { return m_objectsModel; } StereotypesModel *UMLDoc::stereotypesModel() { return m_stereotypesModel; } /** * Ensures the XMI file is a valid UML file. * Currently only checks for metamodel=UML. * * @param headerNode The node */ bool UMLDoc::validateXMI1Header(QDomNode& headerNode) { QDomElement headerElement = headerNode.toElement(); while (!headerNode.isNull()) { /* //Seems older Umbrello files used a different metamodel, so don't validate it for now if(!headerElement.isNull() && headerElement.tagName() == "XMI.metamodel") { String metamodel = headerElement.attribute("xmi.name"); if (metamodel != "UML") { return false; } } */ headerNode = headerNode.nextSibling(); headerElement = headerNode.toElement(); } return true; } /** * Loads all UML objects from XMI into the current UMLDoc. * * @return True if operation successful. */ bool UMLDoc::loadUMLObjectsFromXMI1(QDomElement& element) { /* FIXME need a way to make status bar actually reflect how much of the file has been loaded rather than just counting to 10 (an arbitrary number) emit sigResetStatusbarProgress(); emit sigSetStatusbarProgress(0); emit sigSetStatusbarProgressSteps(10); m_count = 0; */ emit sigWriteToStatusBar(i18n("Loading UML elements...")); // For Umbrello native XMI files, when called from loadFromXMI1() we // get here with Element.tagName() == "UML:Model" from the XMI input: // for (QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) { if (node.isComment()) { continue; } QDomElement tempElement = node.toElement(); QString type = tempElement.tagName(); if (tagEq(type, QLatin1String("Model"))) { // Handling of Umbrello native XMI files: // We get here from a recursive call to loadUMLObjectsFromXMI() // a few lines below, see // if (tagEq(type, "Namespace.ownedElement") .... // Inside this Namespace.ownedElement envelope there are the // four submodels: // // // // // These are ultimately loaded by UMLFolder::loadFromXMI1() // Furthermore, in Umbrello native XMI format this // Namespace.ownedElement is the container of all stereotypes // (). bool foundUmbrelloRootFolder = false; QString name = tempElement.attribute(QLatin1String("name")); for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { if (name == m_root[i]->name()) { m_pCurrentRoot = m_root[i]; m_root[i]->loadFromXMI1(tempElement); foundUmbrelloRootFolder = true; break; } } if (foundUmbrelloRootFolder) { continue; } } if (tagEq(type, QLatin1String("Namespace.ownedElement")) || tagEq(type, QLatin1String("Namespace.contents")) || tagEq(type, QLatin1String("Element.ownedElement")) || // Embarcadero's Describe tagEq(type, QLatin1String("Model"))) { //CHECK: Umbrello currently assumes that nested elements // are ownedElements anyway. // Therefore the tag is of no // significance. // The tagEq(type, "Namespace.contents") and tagEq(type, "Model") // tests do not become true for Umbrello native files, only for // some foreign XMI files. if (!loadUMLObjectsFromXMI1(tempElement)) { uWarning() << "failed load on " << type; return false; } continue; } // From here on, it's support for stereotypes, pre 1.5.5 versions, // and foreign files if (Model_Utils::isCommonXMI1Attribute(type)) { continue; } else if (tagEq(type, QLatin1String("packagedElement")) || tagEq(type, QLatin1String("ownedElement"))) { type = tempElement.attribute(QLatin1String("xmi:type")); } if (!tempElement.hasAttribute(QLatin1String("xmi.id")) && !tempElement.hasAttribute(QLatin1String("xmi:id"))) { QString idref = tempElement.attribute(QLatin1String("xmi.idref")); if (! idref.isEmpty()) { DEBUG(DBG_SRC) << "resolution of xmi.idref " << idref << " is not yet implemented"; } else { uError() << "Cannot load " << type << " because xmi.id is missing"; } continue; } QString stID = tempElement.attribute(QLatin1String("stereotype")); UMLObject *pObject = Object_Factory::makeObjectFromXMI(type, stID); if (!pObject) { uWarning() << "Unknown type of umlobject to create: " << type; // We want a best effort, therefore this is handled as a // soft error. continue; } UMLObject::ObjectType ot = pObject->baseType(); // Set the parent root folder. UMLPackage *pkg = 0; if (ot != UMLObject::ot_Stereotype) { if (ot == UMLObject::ot_Datatype) { pkg = m_datatypeRoot; } else { Uml::ModelType::Enum guess = Model_Utils::guessContainer(pObject); if (guess != Uml::ModelType::N_MODELTYPES) { pkg = m_root[guess]; } else { uError() << "Guess is Uml::ModelType::N_MODELTYPES - package not set correctly for " << pObject->name() << " / base type " << pObject->baseTypeStr(); pkg = m_root[Uml::ModelType::Logical]; } } } pObject->setUMLPackage(pkg); bool status = pObject->loadFromXMI1(tempElement); if (!status) { delete pObject; return false; } pkg = pObject->umlPackage(); if (ot == UMLObject::ot_Stereotype) { UMLStereotype *s = pObject->asUMLStereotype(); UMLStereotype *exist = findStereotype(pObject->name()); if (exist) { if (exist->id() == pObject->id()) { delete pObject; } else { DEBUG(DBG_SRC) << "Stereotype " << pObject->name() << "(id=" << Uml::ID::toString(pObject->id()) << ") already exists with id=" << Uml::ID::toString(exist->id()); addStereotype(s); } } else { addStereotype(s); } continue; } if (pkg) { UMLObjectList &objects = pkg->containedObjects(); if (! objects.contains(pObject)) { DEBUG(DBG_SRC) << "CHECK: adding " << pObject->name() << " to " << pkg->name(); pkg->addObject(pObject); } } else if (ot != UMLObject::ot_Stereotype) { uError() << "Package is NULL for " << pObject->name(); return false; } /* FIXME see comment at loadUMLObjectsFromXMI1 emit sigSetStatusbarProgress(++m_count); */ } return true; } /** * Sets m_nViewID. */ void UMLDoc::setMainViewID(Uml::ID::Type viewID) { m_nViewID = viewID; } /** * Loads umbrello specific extensions from XMI to the UMLDoc. * The extension tags are: "docsettings", "diagrams", "listview", * and "codegeneration". */ void UMLDoc::loadExtensionsFromXMI1(QDomNode& node) { QDomElement element = node.toElement(); QString tag = element.tagName(); if (tag == QLatin1String("docsettings")) { QString viewID = element.attribute(QLatin1String("viewid"), QLatin1String("-1")); m_Doc = element.attribute(QLatin1String("documentation")); QString uniqueid = element.attribute(QLatin1String("uniqueid"), QLatin1String("0")); m_nViewID = Uml::ID::fromString(viewID); UniqueID::set(Uml::ID::fromString(uniqueid)); UMLApp::app()->docWindow()->reset(); } else if (tag == QLatin1String("diagrams") || tag == QLatin1String("UISModelElement")) { // For backward compatibility only: // Since version 1.5.5 diagrams are saved as part of the UMLFolder. QDomNode diagramNode = node.firstChild(); if (tag == QLatin1String("UISModelElement")) { // Unisys.IntegratePlus.2 element = diagramNode.toElement(); tag = element.tagName(); if (tag != QLatin1String("uisOwnedDiagram")) { uError() << "unknown child node " << tag; return; } diagramNode = diagramNode.firstChild(); } else { qreal resolution = 0.0; QString res = node.toElement().attribute(QLatin1String("resolution"), QLatin1String("")); if (!res.isEmpty()) { resolution = res.toDouble(); } if (resolution != 0.0) { UMLApp::app()->document()->setResolution(resolution); } else { // see UMLFolder::loadDiagramsFromXMI() UMLApp::app()->document()->setResolution(0.0); } } if (!loadDiagramsFromXMI1(diagramNode)) { uWarning() << "failed load on diagrams"; } } else if (tag == QLatin1String("listview")) { //FIXME: Need to resolveTypes() before loading listview, // else listview items are duplicated. resolveTypes(); if (!UMLApp::app()->listView()->loadFromXMI1(element)) { uWarning() << "failed load on listview"; } } else if (tag == QLatin1String("codegeneration")) { QDomNode cgnode = node.firstChild(); QDomElement cgelement = cgnode.toElement(); while (!cgelement.isNull()) { QString nodeName = cgelement.tagName(); QString lang = cgelement.attribute(QLatin1String("language"), QLatin1String("UNKNOWN")); Uml::ProgrammingLanguage::Enum pl = Uml::ProgrammingLanguage::fromString(lang); CodeGenerator *g = UMLApp::app()->setGenerator(pl); g->loadFromXMI1(cgelement); cgnode = cgnode.nextSibling(); cgelement = cgnode.toElement(); } if (UMLApp::app()->generator() == 0) { UMLApp::app()->setGenerator(UMLApp::app()->defaultLanguage()); } } } /** * Loads all diagrams from XMI into the current UMLDoc. * For backward compatibility only: * Since version 1.5.5 diagrams are saved as part of the UMLFolder. * * @return True if operation successful. */ bool UMLDoc::loadDiagramsFromXMI1(QDomNode & node) { emit sigWriteToStatusBar(i18n("Loading diagrams...")); emit sigResetStatusbarProgress(); emit sigSetStatusbarProgress(0); emit sigSetStatusbarProgressSteps(10); //FIX ME QDomElement element = node.toElement(); if (element.isNull()) { return true; //return ok as it means there is no umlobjects } const Settings::OptionState state = Settings::optionState(); UMLView * pView = 0; int count = 0; while (!element.isNull()) { QString tag = element.tagName(); if (tag == QLatin1String("diagram") || tag == QLatin1String("UISDiagram")) { pView = new UMLView(0); // IMPORTANT: Set OptionState of new UMLView _BEFORE_ // reading the corresponding diagram: // + allow using per-diagram color and line-width settings // + avoid crashes due to uninitialized values for lineWidth pView->umlScene()->setOptionState(state); bool success = false; if (tag == QLatin1String("UISDiagram")) { success = pView->umlScene()->loadUISDiagram(element); } else { success = pView->umlScene()->loadFromXMI1(element); } if (!success) { uWarning() << "failed load on viewdata loadfromXMI"; delete pView; return false; } // Put diagram in default predefined folder. // @todo pass in the parent folder - it might be a user defined one. Uml::ModelType::Enum mt = Model_Utils::convert_DT_MT(pView->umlScene()->type()); pView->umlScene()->setFolder(m_root[mt]); pView->hide(); addView(pView); emit sigSetStatusbarProgress(++count); qApp->processEvents(); // give UI events a chance } node = node.nextSibling(); element = node.toElement(); } return true; } /** * Call to remove all the views (diagrams) in the current file. */ void UMLDoc::removeAllViews() { for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { m_root[i]->removeAllViews(); } UMLApp::app()->setCurrentView(0); emit sigDiagramChanged(Uml::DiagramType::Undefined); UMLApp::app()->setDiagramMenuItemsState(false); } /** * Call to remove all objects in the current file. */ void UMLDoc::removeAllObjects() { m_root[Uml::ModelType::Logical]->removeObject(m_datatypeRoot); for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { m_root[i]->removeAllObjects(); } } /** * Returns a list of the packages in this UMLDoc, * * @return List of UMLPackages. */ UMLPackageList UMLDoc::packages(bool includeNested /* = true */, Uml::ModelType::Enum model) { UMLPackageList packageList; m_root[model]->appendPackages(packageList, includeNested); return packageList; } /** * Returns the datatype folder. * * @return Pointer to the predefined folder for datatypes. */ UMLFolder * UMLDoc::datatypeFolder() const { return m_datatypeRoot; } /** * Returns a list of the concepts in this UMLDoc. * * @param includeNested Whether to include the concepts from * nested packages (default: true.) * @return List of UML concepts. */ UMLClassifierList UMLDoc::concepts(bool includeNested /* =true */) { UMLClassifierList conceptList; m_root[Uml::ModelType::Logical]->appendClassifiers(conceptList, includeNested); return conceptList; } /** * Returns a list of the classes and interfaces in this UMLDoc. * * @param includeNested Whether to include the concepts from * nested packages (default: true.) * @return List of UML concepts. */ UMLClassifierList UMLDoc::classesAndInterfaces(bool includeNested /* =true */) { UMLClassifierList conceptList; m_root[Uml::ModelType::Logical]->appendClassesAndInterfaces(conceptList, includeNested); return conceptList; } /** * Returns a list of the entities in this UMLDoc. * * @param includeNested Whether to include the entities from * nested packages (default: true.) * @return List of UML Entities. */ UMLEntityList UMLDoc::entities(bool includeNested /* =true */) { UMLEntityList entityList; m_root[Uml::ModelType::EntityRelationship]->appendEntities(entityList, includeNested); return entityList; } /** * Returns a list of the datatypes in this UMLDoc. * * @return List of datatypes. */ UMLClassifierList UMLDoc::datatypes() { UMLObjectList &objects = m_datatypeRoot->containedObjects(); UMLClassifierList datatypeList; foreach (UMLObject *obj, objects) { uIgnoreZeroPointer(obj); if (obj->isUMLDatatype()) { datatypeList.append(obj->asUMLClassifier()); } } return datatypeList; } /** * Returns a list of the associations in this UMLDoc. * * @return List of UML associations. */ UMLAssociationList UMLDoc::associations() { UMLAssociationList associationList; for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { UMLAssociationList assocs = m_root[i]->getAssociations(); foreach (UMLAssociation* a, assocs) { associationList.append(a); } } return associationList; } /** * Controls the printing of the program. * * @param pPrinter The printer (object) to use. * @param selectPage The DiagramPrintPage by which diagrams are selected for printing */ void UMLDoc::print(QPrinter * pPrinter, DiagramPrintPage * selectPage) { UMLView * printView = 0; int count = selectPage->printUmlCount(); QPainter painter(pPrinter); for (int i = 0; i < count; ++i) { if (i>0) { pPrinter->newPage(); } QString sID = selectPage->printUmlDiagram(i); Uml::ID::Type id = Uml::ID::fromString(sID); printView = findView(id); if (printView) { printView->umlScene()->print(pPrinter, painter); } printView = 0; } painter.end(); } /** * Return the list of views for this document. * * @return List of UML views. */ UMLViewList UMLDoc::viewIterator() { UMLViewList accumulator; for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { m_root[i]->appendViews(accumulator, true); } return accumulator; } /** * Sets the modified flag for the document after a modifying * action on the view connected to the document. * * @param modified The value to set the modified flag to. */ void UMLDoc::setModified(bool modified /*=true*/) { if (!m_bLoading) { m_modified = modified; UMLApp::app()->setModified(modified); } } /** * Returns if the document is modified or not. Use this to * determine if your document needs saving by the user on * closing. * * @return True if this UMLDoc is modified. */ bool UMLDoc::isModified() { return m_modified; } /** * Assigns an already created UMLObject a new ID. * If the object is a classifier then the operations/attributes * are also assigned new IDs. * * @param obj Pointer to the UMLObject to add. * @return True if operation successful. */ bool UMLDoc::assignNewIDs(UMLObject* obj) { if (!obj || !m_pChangeLog) { DEBUG(DBG_SRC) << "no obj || Changelog"; return false; } Uml::ID::Type result = assignNewID(obj->id()); obj->setID(result); //If it is a CONCEPT then change the ids of all its operations and attributes if (obj->baseType() == UMLObject::ot_Class) { UMLClassifier *c = obj->asUMLClassifier(); UMLClassifierListItemList attributes = c->getFilteredList(UMLObject::ot_Attribute); foreach (UMLObject* listItem, attributes) { result = assignNewID(listItem->id()); listItem->setID(result); } UMLClassifierListItemList templates = c->getFilteredList(UMLObject::ot_Template); foreach (UMLObject* listItem, templates) { result = assignNewID(listItem->id()); listItem->setID(result); } } if (obj->baseType() == UMLObject::ot_Interface || obj->baseType() == UMLObject::ot_Class) { UMLOperationList operations(((UMLClassifier*)obj)->getOpList()); foreach (UMLObject* listItem, operations) { result = assignNewID(listItem->id()); listItem->setID(result); } } setModified(true); return true; } /** * Return the predefined root folder of the given type. */ UMLFolder *UMLDoc::rootFolder(Uml::ModelType::Enum mt) { if (mt < Uml::ModelType::Logical || mt >= Uml::ModelType::N_MODELTYPES) { uError() << "illegal input value " << Uml::ModelType::toString(mt); return 0; } return m_root[mt]; } /** * Return the corresponding Model_Type if the given object * is one of the root folders. * When the given object is not one of the root folders then * return Uml::ModelType::N_MODELTYPES. */ Uml::ModelType::Enum UMLDoc::rootFolderType(UMLObject *obj) { for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { const Uml::ModelType::Enum m = Uml::ModelType::fromInt(i); if (obj == m_root[m]) { return m; } } return Uml::ModelType::N_MODELTYPES; } /** * Read property of IDChangeLog* m_pChangeLog. * * @return Pointer to the IDChangeLog object. */ IDChangeLog* UMLDoc::changeLog() { return m_pChangeLog; } /** * Opens a Paste session, deletes the old ChangeLog and * creates an empty one. */ void UMLDoc::beginPaste() { if (m_pChangeLog) { delete m_pChangeLog; m_pChangeLog = 0; } m_pChangeLog = new IDChangeLog; } /** * Closes a paste session, deletes the ChangeLog. */ void UMLDoc::endPaste() { if (m_pChangeLog) { delete m_pChangeLog; m_pChangeLog = 0; } } /** * Assigns a New ID to an Object, and also logs the assignment * to its internal ChangeLog. * * @param oldID The present ID of the object. * @return The new ID assigned to the object. */ Uml::ID::Type UMLDoc::assignNewID(Uml::ID::Type oldID) { Uml::ID::Type result = UniqueID::gen(); if (m_pChangeLog) { m_pChangeLog->addIDChange(oldID, result); } return result; } /** * Returns the documentation for the project. * * @return The documentation text of this UMLDoc. */ QString UMLDoc::documentation() const { return m_Doc; } /** * Sets the documentation for the project. * * @param doc The documentation to set for this UMLDoc. */ void UMLDoc::setDocumentation(const QString &doc) { m_Doc = doc; } /** * Adds an already created UMLView to the document, it gets * assigned a new ID, if its name is already in use then the * function appends a number to it to differentiate it from * the others; this number is incremental so if number 1 is in * use then it tries 2 and then 3 and so on * * @param pView Pointer to the UMLView to add. * @return True if operation successful. */ bool UMLDoc::addUMLView(UMLView * pView) { if (!pView || !m_pChangeLog) { return false; } Uml::ID::Type oldID = pView->umlScene()->ID(); int i = 0; QString viewName = pView->umlScene()->name(); QString name = viewName; while (findView(pView->umlScene()->type(), name) != 0) { name = viewName + QLatin1Char('_') + QString::number(++i); } if (i) { //If name was modified pView->umlScene()->setName(name); } Uml::ID::Type newID = assignNewID(oldID); pView->umlScene()->setID(newID); pView->umlScene()->activateAfterLoad(true); pView->umlScene()->endPartialWidgetPaste(); pView->umlScene()->setOptionState(Settings::optionState()); addView(pView); emit sigDiagramCreated(pView->umlScene()->ID()); setModified(true); return true; } /** * Activate all the diagrams/views after loading so all their * widgets keep their IDs. */ void UMLDoc::activateAllViews() { // store old setting - for restore of last setting bool m_bLoading_old = m_bLoading; m_bLoading = true; //this is to prevent document becoming modified when activating a view for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { m_root[i]->activateViews(); } m_bLoading = m_bLoading_old; } /** * Sets the default settings to the given settings. * @param optionState settings */ void UMLDoc::settingsChanged(Settings::OptionState &optionState) { for (int i = 0; i < Uml::ModelType::N_MODELTYPES; ++i) { m_root[i]->setViewOptions(optionState); } initSaveTimer(); } /** * Sets up the autosave timer. */ void UMLDoc::initSaveTimer() { if (m_pAutoSaveTimer) { m_pAutoSaveTimer->stop(); disconnect(m_pAutoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave())); delete m_pAutoSaveTimer; m_pAutoSaveTimer = 0; } Settings::OptionState optionState = Settings::optionState(); if (optionState.generalState.autosave) { m_pAutoSaveTimer = new QTimer(this); connect(m_pAutoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave())); m_pAutoSaveTimer->setSingleShot(false); m_pAutoSaveTimer->start(optionState.generalState.autosavetime * 60000); } } /** * Called after a specified time to autosave the document. */ void UMLDoc::slotAutoSave() { //Only save if modified. if (!m_modified) { return; } #if QT_VERSION >= 0x050000 QUrl tempUrl = m_doc_url; #else KUrl tempUrl = m_doc_url; #endif if (tempUrl.fileName() == i18n("Untitled")) { #if QT_VERSION >= 0x050000 tempUrl.setScheme(QLatin1String("file")); #endif tempUrl.setPath(QDir::homePath() + i18n("/autosave%1", QLatin1String(".xmi"))); saveDocument(tempUrl); setUrlUntitled(); m_modified = true; UMLApp::app()->setModified(m_modified); } else { // 2004-05-17 Achim Spangler #if QT_VERSION >= 0x050000 QUrl orgDocUrl = m_doc_url; #else KUrl orgDocUrl = m_doc_url; #endif QString orgFileName = m_doc_url.fileName(); // don't overwrite manually saved file with autosave content QString fileName = tempUrl.fileName(); Settings::OptionState optionState = Settings::optionState(); fileName.replace(QLatin1String(".xmi"), optionState.generalState.autosavesuffix); #if QT_VERSION >= 0x050000 tempUrl.setUrl(tempUrl.toString(QUrl::RemoveFilename) + fileName); #else tempUrl.setFileName(fileName); #endif // End Achim Spangler saveDocument(tempUrl); // 2004-05-17 Achim Spangler // re-activate m_modified if autosave is writing to other file // than the main project file->autosave-suffix != ".xmi" if (optionState.generalState.autosavesuffix != QLatin1String(".xmi")) { m_modified = true; UMLApp::app()->setModified(m_modified); } // restore original file name - // UMLDoc::saveDocument() sets doc_url to filename which is given as autosave-filename setUrl(orgDocUrl); UMLApp * pApp = UMLApp::app(); pApp->setCaption(orgFileName, isModified()); // End Achim Spangler } } /** * Signal a view/diagram has been renamed. */ void UMLDoc::signalDiagramRenamed(UMLView* view) { if (view) { Settings::OptionState optionState = Settings::optionState(); if (optionState.generalState.tabdiagrams) { UMLApp::app()->tabWidget()->setTabText(UMLApp::app()->tabWidget()->indexOf(view), view->umlScene()->name()); } emit sigDiagramRenamed(view->umlScene()->ID()); } else { uError() << "Cannot signal diagram renamed - view is NULL!"; } } /** * Calls the active code generator to create its default datatypes. */ void UMLDoc::addDefaultDatatypes() { CodeGenerator *cg = UMLApp::app()->generator(); if (cg == 0) { DEBUG(DBG_SRC) << "CodeGenerator is still NULL"; return; } QStringList entries = cg->defaultDatatypes(); QStringList::Iterator end(entries.end()); for (QStringList::Iterator it = entries.begin(); it != end; ++it) { createDatatype(*it); } UMLApp::app()->listView()->closeDatatypesFolder(); } /** * Add a datatype if it doesn't already exist. * Used by code generators and attribute dialog. */ void UMLDoc::createDatatype(const QString &name) { UMLObjectList &datatypes = m_datatypeRoot->containedObjects(); UMLObject* umlobject = Model_Utils::findUMLObject(datatypes, name, UMLObject::ot_Datatype, m_datatypeRoot); if (!umlobject) { Object_Factory::createUMLObject(UMLObject::ot_Datatype, name, m_datatypeRoot); } } /** * Make a popup menu for the tabs * signalled from tabWidget's contextMenu(). */ void UMLDoc::slotDiagramPopupMenu(QWidget* umlview, const QPoint& point) { UMLView* view = (UMLView*) umlview; UMLListViewItem::ListViewType type = UMLListViewItem::lvt_Unknown; switch (view->umlScene()->type()) { case Uml::DiagramType::Class: type = UMLListViewItem::lvt_Class_Diagram; break; case Uml::DiagramType::UseCase: type = UMLListViewItem::lvt_UseCase_Diagram; break; case Uml::DiagramType::Sequence: type = UMLListViewItem::lvt_Sequence_Diagram; break; case Uml::DiagramType::Collaboration: type = UMLListViewItem::lvt_Collaboration_Diagram; break; case Uml::DiagramType::State: type = UMLListViewItem::lvt_State_Diagram; break; case Uml::DiagramType::Activity: type = UMLListViewItem::lvt_Activity_Diagram; break; case Uml::DiagramType::Component: type = UMLListViewItem::lvt_Component_Diagram; break; case Uml::DiagramType::Deployment: type = UMLListViewItem::lvt_Deployment_Diagram; break; case Uml::DiagramType::EntityRelationship: type = UMLListViewItem::lvt_EntityRelationship_Diagram; break; default: uWarning() << "unknown diagram type " << view->umlScene()->type(); return; }//end switch UMLListViewItem item((UMLListView *)0, QString(), type); UMLListViewPopupMenu popup(UMLApp::app()->mainViewWidget(), &item); QAction *triggered = popup.exec(point); view->umlScene()->slotMenuSelection(triggered); } /** * Function for comparing tags in XMI files. */ bool UMLDoc::tagEq (const QString& inTag, const QString& inPattern) { QString tag = inTag; QString pattern = inPattern; tag.remove(QRegExp(QLatin1String("^\\w+:"))); // remove leading "UML:" or other int patSections = pattern.count(QLatin1Char('.')) + 1; QString tagEnd = tag.section(QLatin1Char('.'), -patSections); return (tagEnd.toLower() == pattern.toLower()); } diff --git a/umbrello/umlscene.cpp b/umbrello/umlscene.cpp index d05fe586b..d5f9da4ee 100644 --- a/umbrello/umlscene.cpp +++ b/umbrello/umlscene.cpp @@ -1,4272 +1,4276 @@ /*************************************************************************** * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * copyright (C) 2002-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "umlscene.h" // application specific includes #include "activitywidget.h" #include "actorwidget.h" #include "artifactwidget.h" #include "association.h" #include "associationwidget.h" #include "assocrules.h" #include "attribute.h" #include "boxwidget.h" #include "classifier.h" #include "classifierwidget.h" #include "classoptionspage.h" #include "component.h" #include "cmds.h" #include "componentwidget.h" #include "datatype.h" #include "diagram_utils.h" #include "pinportbase.h" #include "datatypewidget.h" #include "debug_utils.h" #include "dialog_utils.h" #include "docwindow.h" #include "entity.h" #include "entitywidget.h" #include "enumwidget.h" #include "floatingtextwidget.h" #include "folder.h" #include "foreignkeyconstraint.h" #include "forkjoinwidget.h" #include "idchangelog.h" +#include "interfacewidget.h" #include "import_utils.h" #include "layoutgenerator.h" #include "layoutgrid.h" #include "messagewidget.h" #include "model_utils.h" #include "notewidget.h" #include "object_factory.h" #include "objectnodewidget.h" #include "objectwidget.h" #include "package.h" #include "packagewidget.h" #include "pinwidget.h" #include "portwidget.h" #include "seqlinewidget.h" #include "signalwidget.h" #include "statewidget.h" #include "toolbarstate.h" #include "toolbarstatefactory.h" #include "uml.h" #include "umldoc.h" #include "umldragdata.h" #include "umlfiledialog.h" #include "umllistview.h" #include "umllistviewitem.h" #include "umlobject.h" #include "umlobjectlist.h" #include "umlrole.h" #include "umlscenepopupmenu.h" #include "umlview.h" #include "umlviewimageexporter.h" #include "umlwidget.h" #include "uniqueid.h" #include "widget_factory.h" #include "widget_utils.h" #include "widgetlist_utils.h" //kde include files #if QT_VERSION < 0x050000 #include #include #endif #include #include #include // include files for Qt #include #include #include #include #include #include // system includes #include // for ceil // static members const qreal UMLScene::defaultCanvasSize = 5000; bool UMLScene::m_showDocumentationIndicator = false; using namespace Uml; DEBUG_REGISTER(UMLScene) /** * The class UMLScenePrivate is intended to hold private * members/classes to reduce the size of the public class * and to speed up recompiling. * The migration to this class is not complete yet. */ class UMLScenePrivate { public: UMLScenePrivate(UMLScene *parent) : p(parent) { } /** * Check if there is a corresponding port widget * for all UMLPort instances and add if not. */ void addMissingPorts() { UMLWidgetList ports; UMLWidgetList components; foreach(UMLWidget *w, p->widgetList()) { if (w->isPortWidget()) ports.append(w); else if (w->isComponentWidget()) components.append(w); } foreach(UMLWidget *cw, components) { UMLComponent *c = cw->umlObject()->asUMLComponent(); if (!c) continue; // iterate through related ports for this component widget foreach(UMLObject *o, c->containedObjects()) { UMLPort *up = o->asUMLPort(); if (!up) continue; Uml::ID::Type id = o->id(); bool found = false; foreach(UMLWidget *p, ports) { if (p->id() == id) { found = true; break; } } if (!found) new PortWidget(p, up, cw); } } } /** * Check if port are located equally on the border of a component * and fix position if not. */ void fixPortPositions() { foreach(UMLWidget *w, p->widgetList()) { if (w->isPortWidget()) { QGraphicsItem *g = w->parentItem(); ComponentWidget *c = dynamic_cast(g); Q_ASSERT(c); qreal w2 = w->width()/2; qreal h2 = w->height()/2; if (w->x() <= -w2 || w->y() <= -h2 || w->x() >= c->width() - w2 || w->y() >= c->height() - h2) continue; if (w->x() >= c->width() - 3 * w2) { // right w->setX(c->width() - w2); } else if (w->y() >= c->height() - 3 * h2) { // bottom w->setY(c->height() - h2); } else if (w->x() < 3 * w2) { // left w->setX(-w2); } else if (w->y() < 3 * h2) { // top w->setY(-h2); } else uWarning() << "uncatched widget position of" << w->name(); } } } /** * Check if duplicated floating text labels are in the scene and remove them */ void removeDuplicatedFloatingTextInstances() { UMLWidgetList labelsWithoutParents; UMLWidgetList labelsWithParent; uDebug() << "checking diagram" << p->name() << "id" << Uml::ID::toString(p->ID()); foreach(UMLWidget *w, p->widgetList()) { if (!w->isTextWidget()) continue; if (w->parentItem()) labelsWithParent.append(w); else labelsWithoutParents.append(w); } foreach(UMLWidget *w, labelsWithoutParents) { foreach(UMLWidget *wp, labelsWithParent) { if (w->id() == wp->id() && w->localID() == wp->localID() && w->name() == wp->name()) { p->removeWidgetCmd(w); uDebug() << "removed duplicated text label" << w->name() << "id:" << Uml::ID::toString(w->id()); break; } } } } UMLScene *p; }; /** * Constructor. */ UMLScene::UMLScene(UMLFolder *parentFolder, UMLView *view) : QGraphicsScene(0, 0, defaultCanvasSize, defaultCanvasSize), m_nLocalID(Uml::ID::None), m_nID(Uml::ID::None), m_Type(Uml::DiagramType::Undefined), m_Name(QString()), m_Documentation(QString()), m_Options(Settings::optionState()), m_bUseSnapToGrid(false), m_bUseSnapComponentSizeToGrid(false), m_isOpen(true), m_nCollaborationId(0), m_bCreateObject(false), m_bDrawSelectedOnly(false), m_bPaste(false), m_bStartedCut(false), m_d(new UMLScenePrivate(this)), m_view(view), m_pFolder(parentFolder), m_pIDChangesLog(0), m_isActivated(false), m_bPopupShowing(false), m_autoIncrementSequence(false) { m_PastePoint = QPointF(0, 0); m_pImageExporter = new UMLViewImageExporter(this); // setup signals connect(UMLApp::app(), SIGNAL(sigCutSuccessful()), this, SLOT(slotCutSuccessful())); // Create the ToolBarState factory. This class is not a singleton, because it // needs a pointer to this object. m_pToolBarStateFactory = new ToolBarStateFactory(); m_pToolBarState = m_pToolBarStateFactory->getState(WorkToolBar::tbb_Arrow, this); m_doc = UMLApp::app()->document(); // // settings for background // setBackgroundBrush(QColor(195, 195, 195)); m_layoutGrid = new LayoutGrid(this); // fix crash caused by Qt stale item issue see https://bugs.kde.org/show_bug.cgi?id=383592 setItemIndexMethod(NoIndex); } /** * Destructor. */ UMLScene::~UMLScene() { delete m_pImageExporter; m_pImageExporter = 0; delete m_pIDChangesLog; m_pIDChangesLog = 0; // before we can delete the QCanvas, all widgets must be explicitly // removed // otherwise the implicit remove of the contained widgets will cause // events which would demand a valid connected QCanvas // ==> this causes umbrello to crash for some - larger?? - projects // first avoid all events, which would cause some update actions // on deletion of each removed widget blockSignals(true); removeAllWidgets(); delete m_pToolBarStateFactory; m_pToolBarStateFactory = 0; delete m_layoutGrid; delete m_d; } /** * Return the UMLFolder in which this diagram lives. */ UMLFolder* UMLScene::folder() const { return m_pFolder; } /** * Set the UMLFolder in which this diagram lives. */ void UMLScene::setFolder(UMLFolder *folder) { m_pFolder = folder; } /** * Returns the active view associated with this scene. */ UMLView* UMLScene::activeView() const { return m_view; } /** * Return the documentation of the diagram. */ QString UMLScene::documentation() const { return m_Documentation; } /** * Set the documentation of the diagram. */ void UMLScene::setDocumentation(const QString &doc) { m_Documentation = doc; } /** * Return the state of the auto increment sequence */ bool UMLScene::autoIncrementSequence() const { return m_autoIncrementSequence; } void UMLScene::setAutoIncrementSequence(bool state) { m_autoIncrementSequence = state; } /** * Return the next auto increment sequence value */ QString UMLScene::autoIncrementSequenceValue() { int sequenceNumber = 0; if (type() == Uml::DiagramType::Sequence) { foreach (MessageWidget* message, messageList()) { bool ok; int value = message->sequenceNumber().toInt(&ok); if (ok && value > sequenceNumber) sequenceNumber = value; } } else if (type() == Uml::DiagramType::Collaboration) { foreach (AssociationWidget* assoc, associationList()) { bool ok; int value = assoc->sequenceNumber().toInt(&ok); if (ok && value > sequenceNumber) sequenceNumber = value; } } return QString::number(sequenceNumber + 1); } /** * Return the name of the diagram. */ QString UMLScene::name() const { return m_Name; } /** * Set the name of the diagram. */ void UMLScene::setName(const QString &name) { m_Name = name; } /** * Returns the type of the diagram. */ DiagramType::Enum UMLScene::type() const { return m_Type; } /** * Set the type of diagram. */ void UMLScene::setType(DiagramType::Enum type) { m_Type = type; } /** * Returns the ID of the diagram. */ Uml::ID::Type UMLScene::ID() const { return m_nID; } /** * Sets the ID of the diagram. */ void UMLScene::setID(Uml::ID::Type id) { m_nID = id; } /** * Returns the position of the diagram. */ QPointF UMLScene::pos() const { return m_Pos; } /** * Sets the position of the diagram. */ void UMLScene::setPos(const QPointF &pos) { m_Pos = pos; } /** * Returns the fill color to use. */ const QColor& UMLScene::fillColor() const { return m_Options.uiState.fillColor; } /** * Set the background color. * * @param color The color to use. */ void UMLScene::setFillColor(const QColor &color) { m_Options.uiState.fillColor = color; emit sigFillColorChanged(ID()); } /** * Returns the line color to use. */ const QColor& UMLScene::lineColor() const { return m_Options.uiState.lineColor; } /** * Sets the line color. * * @param color The color to use. */ void UMLScene::setLineColor(const QColor &color) { m_Options.uiState.lineColor = color; emit sigLineColorChanged(ID()); } /** * Returns the line width to use. */ uint UMLScene::lineWidth() const { return m_Options.uiState.lineWidth; } /** * Sets the line width. * * @param width The width to use. */ void UMLScene::setLineWidth(uint width) { m_Options.uiState.lineWidth = width; emit sigLineWidthChanged(ID()); } /** * Returns the text color to use. */ const QColor& UMLScene::textColor() const { return m_Options.uiState.textColor; } /** * Sets the text color. * * @param color The color to use. */ void UMLScene::setTextColor(const QColor& color) { m_Options.uiState.textColor = color; emit sigTextColorChanged(ID()); } /** * return grid dot color * * @return Color */ const QColor& UMLScene::gridDotColor() const { return m_layoutGrid->gridDotColor(); } /** * set grid dot color * * @param color grid dot color */ void UMLScene::setGridDotColor(const QColor& color) { m_Options.uiState.gridDotColor = color; m_layoutGrid->setGridDotColor(color); } /** * Returns the options being used. */ Settings::OptionState& UMLScene::optionState() { return m_Options; } /** * Sets the options to be used. */ void UMLScene::setOptionState(const Settings::OptionState& options) { m_Options = options; setBackgroundBrush(options.uiState.backgroundColor); setGridDotColor(options.uiState.gridDotColor); } /** * Returns a reference to the association list. */ const AssociationWidgetList UMLScene::associationList() const { AssociationWidgetList result; foreach(QGraphicsItem *item, items()) { AssociationWidget *w = dynamic_cast(item); if (w) result.append(w); } return result; } /** * Returns a reference to the widget list. */ const UMLWidgetList UMLScene::widgetList() const { UMLWidgetList result; foreach(QGraphicsItem *item, items()) { UMLWidget *w = dynamic_cast(item); if (w && !w->isMessageWidget() && !w->isAssociationWidget()) result.append(w); } return result; } void UMLScene::addWidgetCmd(UMLWidget* widget) { Q_ASSERT(0 != widget); addItem(widget); } void UMLScene::addWidgetCmd(AssociationWidget* widget) { Q_ASSERT(0 != widget); addItem(widget); } /** * Returns a reference to the message list. */ const MessageWidgetList UMLScene::messageList() const { MessageWidgetList result; foreach(QGraphicsItem *item, items()) { MessageWidget *w = dynamic_cast(item); if (w) result.append(w); } return result; } /** * Used for creating unique name of collaboration messages. */ int UMLScene::generateCollaborationId() { return ++m_nCollaborationId; } /** * Returns the open state. * @return when true diagram is shown to the user */ bool UMLScene::isOpen() const { return m_isOpen; } /** * Sets the flag 'isOpen'. * @param isOpen flag indicating that the diagram is shown to the user */ void UMLScene::setIsOpen(bool isOpen) { m_isOpen = isOpen; } /** * Contains the implementation for printing functionality. */ void UMLScene::print(QPrinter *pPrinter, QPainter & pPainter) { bool isFooter = optionState().generalState.footerPrinting; // The printer will probably use a different font with different font metrics, // force the widgets to update accordingly on paint forceUpdateWidgetFontMetrics(&pPainter); QRectF source = diagramRect(); QRect paper = pPrinter->paperRect(); QRect page = pPrinter->pageRect(); // use the painter font metrics, not the screen fm! QFontMetrics fm = pPainter.fontMetrics(); int fontHeight = fm.lineSpacing(); if (paper == page) { QSize margin = page.size() * 0.025; page.adjust(margin.width(), margin.height(), -margin.width(), -margin.height()); } if (isFooter) { int margin = 3 + 3 * fontHeight; page.adjust(0, 0, 0, -margin); } getDiagram(pPainter, QRectF(source), QRectF(page)); //draw foot note if (isFooter) { page.adjust(0, 0, 0, fontHeight); QString string = i18n("Diagram: %2 Page %1", 1, name()); QColor textColor(50, 50, 50); pPainter.setPen(textColor); pPainter.drawLine(page.left(), page.bottom() , page.right(), page.bottom()); pPainter.drawText(page.left(), page.bottom() + 3, page.right(), 2*fontHeight, Qt::AlignLeft, string); } // next painting will most probably be to a different device (i.e. the screen) forceUpdateWidgetFontMetrics(0); } /** * Initialize and announce a newly created widget. * Auxiliary to contentsMouseReleaseEvent(). */ void UMLScene::setupNewWidget(UMLWidget *w, bool setPosition) { if (setPosition && (!w->isPinWidget()) && (!w->isPortWidget()) && (!w->isObjectWidget())) { // ObjectWidget's position is handled by the widget w->setX(m_Pos.x()); w->setY(m_Pos.y()); } w->setVisible(true); w->activate(); w->setFontCmd(font()); w->slotFillColorChanged(ID()); w->slotTextColorChanged(ID()); w->slotLineWidthChanged(ID()); resizeSceneToItems(); m_doc->setModified(); if (m_doc->loading()) { // do not emit signals while loading addWidgetCmd(w); // w->activate(); // will be done by UMLDoc::activateAllViews() after loading } else { UMLApp::app()->executeCommand(new CmdCreateWidget(w)); } } /** * Return whether we are currently creating an object. */ bool UMLScene::getCreateObject() const { return m_bCreateObject; } /** * Set whether we are currently creating an object. */ void UMLScene::setCreateObject(bool bCreate) { m_bCreateObject = bCreate; } /** * Overrides the standard operation. */ void UMLScene::showEvent(QShowEvent* /*se*/) { connect(m_doc, SIGNAL(sigObjectCreated(UMLObject*)), this, SLOT(slotObjectCreated(UMLObject*))); connect(this, SIGNAL(sigAssociationRemoved(AssociationWidget*)), UMLApp::app()->docWindow(), SLOT(slotAssociationRemoved(AssociationWidget*))); connect(this, SIGNAL(sigWidgetRemoved(UMLWidget*)), UMLApp::app()->docWindow(), SLOT(slotWidgetRemoved(UMLWidget*))); } /** * Overrides the standard operation. */ void UMLScene::hideEvent(QHideEvent* /*he*/) { disconnect(m_doc, SIGNAL(sigObjectCreated(UMLObject*)), this, SLOT(slotObjectCreated(UMLObject*))); disconnect(this, SIGNAL(sigAssociationRemoved(AssociationWidget*)), UMLApp::app()->docWindow(), SLOT(slotAssociationRemoved(AssociationWidget*))); disconnect(this, SIGNAL(sigWidgetRemoved(UMLWidget*)), UMLApp::app()->docWindow(), SLOT(slotWidgetRemoved(UMLWidget*))); } /** * Changes the current tool to the selected tool. * The current tool is cleaned and the selected tool initialized. */ void UMLScene::slotToolBarChanged(int c) { m_pToolBarState->cleanBeforeChange(); m_pToolBarState = m_pToolBarStateFactory->getState((WorkToolBar::ToolBar_Buttons)c, this); m_pToolBarState->init(); m_bPaste = false; } /** * Slot called when an object is created. * @param o created UML object */ void UMLScene::slotObjectCreated(UMLObject* o) { DEBUG(DBG_SRC) << "scene=" << name() << " / object=" << o->name(); m_bPaste = false; //check to see if we want the message //may be wanted by someone else e.g. list view if (!m_bCreateObject) { return; } UMLWidget* newWidget = Widget_Factory::createWidget(this, o); if (!newWidget) { return; } setupNewWidget(newWidget); m_bCreateObject = false; if (Model_Utils::hasAssociations(o->baseType())) { createAutoAssociations(newWidget); // We need to invoke createAutoAttributeAssociations() // on all other widgets again because the newly created // widget might saturate some latent attribute assocs. createAutoAttributeAssociations2(newWidget); } resizeSceneToItems(); } /** * Slot called when an object is removed. * @param o removed UML object */ void UMLScene::slotObjectRemoved(UMLObject * o) { m_bPaste = false; Uml::ID::Type id = o->id(); foreach(UMLWidget* obj, widgetList()) { if (obj->id() != id) continue; removeWidget(obj); break; } } /** * Override standard method. */ void UMLScene::dragEnterEvent(QGraphicsSceneDragDropEvent *e) { UMLDragData::LvTypeAndID_List tidList; if (!UMLDragData::getClip3TypeAndID(e->mimeData(), tidList)) { DEBUG(DBG_SRC) << "UMLDragData::getClip3TypeAndID returned false"; return; } for(UMLDragData::LvTypeAndID_List::const_iterator it = tidList.begin(); it != tidList.end(); it++) { UMLListViewItem::ListViewType lvtype = (*it)->type; Uml::ID::Type id = (*it)->id; DiagramType::Enum diagramType = type(); UMLObject* temp = 0; //if dragging diagram - might be a drag-to-note if (Model_Utils::typeIsDiagram(lvtype)) { e->accept(); continue; } //can't drag anything onto state/activity diagrams if (diagramType == DiagramType::State || diagramType == DiagramType::Activity) { e->ignore(); continue; } //make sure can find UMLObject if (!(temp = m_doc->findObjectById(id))) { DEBUG(DBG_SRC) << "object " << Uml::ID::toString(id) << " not found"; e->ignore(); continue; } bool bAccept = Model_Utils::typeIsAllowedInDiagram(temp, this); if (bAccept) { e->accept(); } else { e->ignore(); } } } /** * Override standard method. */ void UMLScene::dragMoveEvent(QGraphicsSceneDragDropEvent* e) { e->accept(); } /** * Override standard method. */ void UMLScene::dropEvent(QGraphicsSceneDragDropEvent *e) { UMLDragData::LvTypeAndID_List tidList; if (!UMLDragData::getClip3TypeAndID(e->mimeData(), tidList)) { DEBUG(DBG_SRC) << "UMLDragData::getClip3TypeAndID returned error"; return; } m_Pos = e->scenePos(); for(UMLDragData::LvTypeAndID_List::const_iterator it = tidList.begin(); it != tidList.end(); it++) { UMLListViewItem::ListViewType lvtype = (*it)->type; Uml::ID::Type id = (*it)->id; if (Model_Utils::typeIsDiagram(lvtype)) { bool breakFlag = false; UMLWidget* w = 0; foreach(w, widgetList()) { if (w->isNoteWidget() && w->onWidget(e->scenePos())) { breakFlag = true; break; } } if (breakFlag) { NoteWidget *note = static_cast(w); note->setDiagramLink(id); } continue; } UMLObject* o = m_doc->findObjectById(id); if (!o) { DEBUG(DBG_SRC) << "object id=" << Uml::ID::toString(id) << " not found"; continue; } UMLWidget* newWidget = Widget_Factory::createWidget(this, o); if (!newWidget) { uWarning() << "could not create widget for uml object" << o->name(); continue; } setupNewWidget(newWidget); m_Pos += QPointF(UMLWidget::DefaultMinimumSize.width(), UMLWidget::DefaultMinimumSize.height()); createAutoAssociations(newWidget); createAutoAttributeAssociations2(newWidget); } } /** * Overrides the standard operation. * Calls the same method in the current tool bar state. */ void UMLScene::mouseMoveEvent(QGraphicsSceneMouseEvent* ome) { m_pToolBarState->mouseMove(ome); } /** * Override standard method. * Calls the same method in the current tool bar state. */ void UMLScene::mousePressEvent(QGraphicsSceneMouseEvent* event) { if (event->button() != Qt::LeftButton) { event->ignore(); return; } m_pToolBarState->mousePress(event); //TODO should be managed by widgets when are selected. Right now also has some //problems, such as clicking on a widget, and clicking to move that widget shows //documentation of the diagram instead of keeping the widget documentation. //When should diagram documentation be shown? When clicking on an empty //space in the diagram with arrow tool? UMLWidget* widget = widgetAt(event->scenePos()); if (widget) { DEBUG(DBG_SRC) << "widget = " << widget->name() << " / type = " << widget->baseTypeStr(); UMLApp::app()->docWindow()->showDocumentation(widget); event->accept(); } else { AssociationWidget* association = associationAt(event->scenePos()); if (association) { DEBUG(DBG_SRC) << "association widget = " << association->name() << " / type = " << association->baseTypeStr(); // the following is done in AssociationWidget::setSelected() // UMLApp::app()->docWindow()->showDocumentation(association, true); // event->accept(); } //:TODO: else if (clicking on other elements with documentation) { //:TODO: UMLApp::app()->docWindow()->showDocumentation(umlObject, true); else { // clicking on an empty space in the diagram with arrow tool UMLApp::app()->docWindow()->showDocumentation(this); event->accept(); } } } /** * Override standard method. * Calls the same method in the current tool bar state. */ void UMLScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) { if (!m_doc->loading()) m_pToolBarState->mouseDoubleClick(event); if (!event->isAccepted()) { // show properties dialog of the scene if (m_view->showPropertiesDialog() == true) { m_doc->setModified(); } event->accept(); } } /** * Overrides the standard operation. * Calls the same method in the current tool bar state. */ void UMLScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* ome) { m_pToolBarState->mouseRelease(ome); } /** * Determine whether on a sequence diagram we have clicked on a line * of an Object. * * @return The widget owning the line which was clicked. * Returns 0 if no line was clicked on. */ ObjectWidget * UMLScene::onWidgetLine(const QPointF &point) const { foreach(UMLWidget* obj, widgetList()) { ObjectWidget *ow = obj->asObjectWidget(); if (ow == 0) continue; SeqLineWidget *pLine = ow->sequentialLine(); if (pLine == 0) { uError() << "SeqLineWidget of " << ow->name() << " (id=" << Uml::ID::toString(ow->localID()) << ") is NULL"; continue; } if (pLine->onWidget(point)) return ow; } return 0; } /** * Determine whether on a sequence diagram we have clicked on * the destruction box of an Object. * * @return The widget owning the destruction box which was clicked. * Returns 0 if no destruction box was clicked on. */ ObjectWidget * UMLScene::onWidgetDestructionBox(const QPointF &point) const { foreach(UMLWidget* obj, widgetList()) { ObjectWidget *ow = obj->asObjectWidget(); if (ow == 0) continue; SeqLineWidget *pLine = ow->sequentialLine(); if (pLine == 0) { uError() << "SeqLineWidget of " << ow->name() << " (id=" << Uml::ID::toString(ow->localID()) << ") is NULL"; continue; } if (pLine->onDestructionBox(point)) return ow; } return 0; } /** * Return pointer to the first selected widget (for multi-selection) */ UMLWidget* UMLScene::getFirstMultiSelectedWidget() const { if (selectedWidgets().size() == 0) return 0; return selectedWidgets().first(); } /** * Tests the given point against all widgets and returns the * widget for which the point is within its bounding rectangle. * In case of multiple matches, returns the smallest widget. * Returns NULL if the point is not inside any widget. * TODO: What about using QGraphicsScene::items(...)? */ UMLWidget* UMLScene::widgetAt(const QPointF& p) { return dynamic_cast(itemAt(p)); } /** * Tests the given point against all associations and returns the * association widget for which the point is on the line. * Returns NULL if the point is not inside any association. * CHECK: This is the same method as in ToolBarState. */ AssociationWidget* UMLScene::associationAt(const QPointF& p) { foreach (AssociationWidget* association, associationList()) { if (association->onAssociation(p)) { return association; } } return 0; } /** * Tests the given point against all associations and returns the * association widget for which the point is on the line. * Returns NULL if the point is not inside any association. */ MessageWidget* UMLScene::messageAt(const QPointF& p) { foreach(MessageWidget *message, messageList()) { if (message->onWidget(p)) { return message; } } return 0; } /** * Sees if a message is relevant to the given widget. If it does delete it. * @param w The widget to check messages against. */ void UMLScene::checkMessages(ObjectWidget * w) { if (type() != DiagramType::Sequence) { return; } foreach(MessageWidget *obj, messageList()) { if (obj->hasObjectWidget(w)) { removeWidgetCmd(obj); } } } /** * Returns whether a widget is already on the diagram. * * @param id The id of the widget to check for. * * @return Returns pointer to the widget if it is on the diagram, NULL if not. */ UMLWidget* UMLScene::widgetOnDiagram(Uml::ID::Type id) { foreach(UMLWidget *obj, widgetList()) { if (!obj) continue; UMLWidget* w = obj->widgetWithID(id); if (w) return w; } foreach(UMLWidget *obj, messageList()) { // CHECK: Should MessageWidget reimplement widgetWithID() ? // If yes then we should use obj->widgetWithID(id) here too. if (id == obj->id()) return obj; } return 0; } /** * Finds a widget with the given ID. * Search both our UMLWidget AND MessageWidget lists. * @param id The ID of the widget to find. * * @return Returns the widget found, returns 0 if no widget found. */ UMLWidget * UMLScene::findWidget(Uml::ID::Type id) { foreach(UMLWidget* obj, widgetList()) { if (!obj) continue; UMLWidget* w = obj->widgetWithID(id); if (w) { return w; } } foreach(UMLWidget* obj, messageList()) { // CHECK: Should MessageWidget reimplement widgetWithID() ? // If yes then we should use obj->widgetWithID(id) here too. if (obj->localID() == id || obj->id() == id) return obj; } return 0; } /** * Finds an association widget with the given ID. * * @param id The ID of the widget to find. * * @return Returns the widget found, returns 0 if no widget found. */ AssociationWidget * UMLScene::findAssocWidget(Uml::ID::Type id) { foreach(AssociationWidget* obj, associationList()) { UMLAssociation* umlassoc = obj->association(); if (umlassoc && umlassoc->id() == id) { return obj; } } return 0; } /** * Finds an association widget with the given widgets and the given role B name. * Considers the following association types: * at_Association, at_UniAssociation, at_Composition, at_Aggregation * This is used for seeking an attribute association. * * @param pWidgetA Pointer to the UMLWidget of role A. * @param pWidgetB Pointer to the UMLWidget of role B. * @param roleNameB Name at the B side of the association (the attribute name) * * @return Returns the widget found, returns 0 if no widget found. */ AssociationWidget * UMLScene::findAssocWidget(UMLWidget *pWidgetA, UMLWidget *pWidgetB, const QString& roleNameB) { foreach(AssociationWidget* assoc, associationList()) { const Uml::AssociationType::Enum testType = assoc->associationType(); if (testType != Uml::AssociationType::Association && testType != Uml::AssociationType::UniAssociation && testType != Uml::AssociationType::Composition && testType != Uml::AssociationType::Aggregation && testType != Uml::AssociationType::Relationship) { continue; } if (pWidgetA->id() == assoc->widgetIDForRole(Uml::RoleType::A) && pWidgetB->id() == assoc->widgetIDForRole(Uml::RoleType::B) && assoc->roleName(Uml::RoleType::B) == roleNameB) { return assoc; } } return 0; } /** * Finds an association widget with the given type and widgets. * * @param at The AssociationType of the widget to find. * @param pWidgetA Pointer to the UMLWidget of role A. * @param pWidgetB Pointer to the UMLWidget of role B. * * @return Returns the widget found, returns 0 if no widget found. */ AssociationWidget * UMLScene::findAssocWidget(AssociationType::Enum at, UMLWidget *pWidgetA, UMLWidget *pWidgetB) { foreach(AssociationWidget* assoc, associationList()) { Uml::AssociationType::Enum testType = assoc->associationType(); if (testType != at) { continue; } if (pWidgetA->id() == assoc->widgetIDForRole(Uml::RoleType::A) && pWidgetB->id() == assoc->widgetIDForRole(Uml::RoleType::B)) { return assoc; } } return 0; } /** * Remove a widget from view (undo command) * * @param o The widget to remove. */ void UMLScene::removeWidget(UMLWidget * o) { UMLApp::app()->executeCommand(new CmdRemoveWidget(o)); } /** * Remove a widget from view. * * @param o The widget to remove. */ void UMLScene::removeWidgetCmd(UMLWidget * o) { if (!o) return; emit sigWidgetRemoved(o); removeAssociations(o); removeOwnedWidgets(o); WidgetBase::WidgetType t = o->baseType(); if (type() == DiagramType::Sequence && t == WidgetBase::wt_Object) { checkMessages(static_cast(o)); } o->cleanup(); o->setSelectedFlag(false); disconnect(this, SIGNAL(sigFillColorChanged(Uml::ID::Type)), o, SLOT(slotFillColorChanged(Uml::ID::Type))); disconnect(this, SIGNAL(sigLineColorChanged(Uml::ID::Type)), o, SLOT(slotLineColorChanged(Uml::ID::Type))); disconnect(this, SIGNAL(sigTextColorChanged(Uml::ID::Type)), o, SLOT(slotTextColorChanged(Uml::ID::Type))); removeItem(o); o->deleteLater(); m_doc->setModified(true); } /** * Remove all widgets that have given widget as owner. * * @param o The owner widget that will be removed. */ void UMLScene::removeOwnedWidgets(UMLWidget* o) { foreach(QGraphicsItem* item, o->childItems()) { UMLWidget* widget = dynamic_cast(item); if ((widget != 0) && (widget->isPinWidget() || widget->isPortWidget())) { removeWidgetCmd(widget); } } } /** * Returns background color */ const QColor& UMLScene::backgroundColor() const { return backgroundBrush().color(); } /** * Returns whether to use the fill/background color */ bool UMLScene::useFillColor() const { return m_Options.uiState.useFillColor; } /** * Sets whether to use the fill/background color */ void UMLScene::setUseFillColor(bool ufc) { m_Options.uiState.useFillColor = ufc; } /** * Gets the smallest area to print. * * @return Returns the smallest area to print. */ QRectF UMLScene::diagramRect() { return itemsBoundingRect(); } /** * Returns a list of selected widgets * @return list of selected widgets based on class UMLWidget * @note This method returns widgets including message widgets, but no association widgets */ UMLWidgetList UMLScene::selectedWidgets() const { QList items = selectedItems(); UMLWidgetList widgets; foreach(QGraphicsItem *item, items) { UMLWidget *w = dynamic_cast(item); if (w) widgets.append(w); } return widgets; } /** * Returns a list of selected association widgets * @return list of selected widgets based on class AssociationWidget */ AssociationWidgetList UMLScene::selectedAssociationWidgets() const { QList items = selectedItems(); AssociationWidgetList widgets; foreach(QGraphicsItem *item, items) { AssociationWidget *w = dynamic_cast(item); if (w) widgets.append(w); } return widgets; } /** * Returns a list of selected message widgets * @return list of selected widgets based on class MessageWidget */ UMLWidgetList UMLScene::selectedMessageWidgets() const { QList items = selectedItems(); UMLWidgetList widgets; foreach(QGraphicsItem *item, items) { MessageWidget *w = dynamic_cast(item); if (w) widgets.append(w); } return widgets; } /** * Clear the selected widgets list. */ void UMLScene::clearSelected() { clearSelection(); //m_doc->enableCutCopy(false); } /** * Move all the selected widgets by a relative X and Y offset. * TODO: Only used in UMLApp::handleCursorKeyReleaseEvent * * @param dX The distance to move horizontally. * @param dY The distance to move vertically. */ void UMLScene::moveSelectedBy(qreal dX, qreal dY) { // DEBUG(DBG_SRC) << "********** m_selectedList count=" << m_selectedList.count(); foreach(UMLWidget *w, selectedWidgets()) { w->moveByLocal(dX, dY); } } /** * Set the useFillColor variable to all selected widgets * * @param useFC The state to set the widget to. */ void UMLScene::selectionUseFillColor(bool useFC) { if (useFC) { UMLApp::app()->beginMacro(i18n("Use fill color")); } else { UMLApp::app()->beginMacro(i18n("No fill color")); } foreach(UMLWidget* widget, selectedWidgets()) { widget->setUseFillColor(useFC); } UMLApp::app()->endMacro(); } /** * Set the font for all the currently selected items. */ void UMLScene::selectionSetFont(const QFont &font) { UMLApp::app()->beginMacro(i18n("Change font")); foreach(UMLWidget* temp, selectedWidgets()) { temp->setFont(font); } UMLApp::app()->endMacro(); } /** * Set the line color for all the currently selected items. */ void UMLScene::selectionSetLineColor(const QColor &color) { UMLApp::app()->beginMacro(i18n("Change line color")); foreach(UMLWidget *temp, selectedWidgets()) { temp->setLineColor(color); } AssociationWidgetList assoclist = selectedAssocs(); foreach(AssociationWidget *aw, assoclist) { aw->setLineColor(color); } UMLApp::app()->endMacro(); } /** * Set the line width for all the currently selected items. */ void UMLScene::selectionSetLineWidth(uint width) { UMLApp::app()->beginMacro(i18n("Change line width")); foreach(UMLWidget* temp, selectedWidgets()) { temp->setLineWidth(width); temp->setUsesDiagramLineWidth(false); } AssociationWidgetList assoclist = selectedAssocs(); foreach(AssociationWidget *aw, assoclist) { aw->setLineWidth(width); aw->setUsesDiagramLineWidth(false); } UMLApp::app()->endMacro(); } /** * Set the fill color for all the currently selected items. */ void UMLScene::selectionSetFillColor(const QColor &color) { UMLApp::app()->beginMacro(i18n("Change fill color")); foreach(UMLWidget* widget, selectedWidgets()) { widget->setFillColor(color); widget->setUsesDiagramFillColor(false); } UMLApp::app()->endMacro(); } /** * Set or unset the visual property (show ..) setting of all selected items. */ void UMLScene::selectionSetVisualProperty(ClassifierWidget::VisualProperty property, bool value) { UMLApp::app()->beginMacro(i18n("Change visual property")); foreach(UMLWidget *temp, selectedWidgets()) { ClassifierWidget *cw = temp->asClassifierWidget(); cw->setVisualProperty(property, value); } UMLApp::app()->endMacro(); } /** * Unselect child widgets when their owner is already selected. */ void UMLScene::unselectChildrenOfSelectedWidgets() { foreach(UMLWidget* widget, selectedWidgets()) { if (widget->isPinWidget() || widget->isPortWidget()) { foreach(UMLWidget* potentialParentWidget, selectedWidgets()) { if (widget->parentItem() == potentialParentWidget) { widget->setSelectedFlag(false); } } } } } /** * Delete the selected widgets list and the widgets in it. */ void UMLScene::deleteSelection() { AssociationWidgetList selectedAssociations = selectedAssociationWidgets(); int selectionCount = selectedWidgets().count() + selectedAssociations.count(); if (selectionCount == 0) return; // check related associations bool hasAssociations = false; foreach(UMLWidget* widget, selectedWidgets()) { if (widget->isTextWidget() && widget->asFloatingTextWidget()->textRole() != Uml::TextRole::Floating) { continue; } if (widget->isMessageWidget() || widget->associationWidgetList().size() > 0) hasAssociations = true; } if (hasAssociations && !Dialog_Utils::askDeleteAssociation()) return; UMLApp::app()->beginMacro(i18n("Delete widgets")); unselectChildrenOfSelectedWidgets(); foreach(UMLWidget* widget, selectedWidgets()) { // Don't delete text widget that are connect to associations as these will // be cleaned up by the associations. if (widget->isTextWidget() && widget->asFloatingTextWidget()->textRole() != Uml::TextRole::Floating) { widget->setSelectedFlag(false); widget->hide(); } else if (widget->isPortWidget()) { UMLObject *o = widget->umlObject(); removeWidget(widget); if (o) UMLApp::app()->executeCommand(new CmdRemoveUMLObject(o)); // message widgets are handled later } else if (!widget->isMessageWidget()){ removeWidget(widget); } } // Delete any selected associations. foreach(AssociationWidget* assocwidget, selectedAssociations) { removeWidgetCmd(assocwidget); } // we also have to remove selected messages from sequence diagrams foreach(UMLWidget* cur_msgWgt, selectedMessageWidgets()) { removeWidget(cur_msgWgt); } //make sure list empty - it should be anyway, just a check. clearSelected(); UMLApp::app()->endMacro(); } /** * resize selected widgets */ void UMLScene::resizeSelection() { int selectionCount = selectedWidgets().count(); if (selectionCount > 1) { UMLApp::app()->beginMacro(i18n("Resize widgets")); } if (selectedCount() == 0) return; foreach(UMLWidget *w, selectedWidgets()) { w->resize(); } m_doc->setModified(); if (selectionCount > 1) { UMLApp::app()->endMacro(); } } /** * Selects all widgets */ void UMLScene::selectAll() { selectWidgets(sceneRect().left(), sceneRect().top(), sceneRect().right(), sceneRect().bottom()); } /** * Returns true if this diagram resides in an externalized folder. * CHECK: It is probably cleaner to move this to the UMLListViewItem. */ bool UMLScene::isSavedInSeparateFile() { if (optionState().generalState.tabdiagrams) { // Umbrello currently does not support external folders // when tabbed diagrams are enabled. return false; } const QString msgPrefix(QLatin1String("UMLScene::isSavedInSeparateFile(") + name() + QLatin1String("): ")); UMLListView *listView = UMLApp::app()->listView(); UMLListViewItem *lvItem = listView->findItem(m_nID); if (lvItem == 0) { uError() << msgPrefix << "listView->findUMLObject(this) returns false"; return false; } UMLListViewItem *parentItem = dynamic_cast(lvItem->parent()); if (parentItem == 0) { uError() << msgPrefix << "parent item in listview is not a UMLListViewItem (?)"; return false; } const UMLListViewItem::ListViewType lvt = parentItem->type(); if (! Model_Utils::typeIsFolder(lvt)) return false; UMLFolder *modelFolder = parentItem->umlObject()->asUMLFolder(); if (modelFolder == 0) { uError() << msgPrefix << "parent model object is not a UMLFolder (?)"; return false; } QString folderFile = modelFolder->folderFile(); return !folderFile.isEmpty(); } UMLSceneItemList UMLScene::collisions(const QPointF &p, int delta) { QPointF a = p-QPointF(delta, delta); QPointF b = p+QPointF(delta, delta); QList list = items(QRectF(a, b)); return list; } /** * Calls setSelected on the given UMLWidget and enters * it into the m_selectedList while making sure it is * there only once. */ void UMLScene::makeSelected(UMLWidget* uw) { if (uw) { uw->setSelected(true); } } /** * Selects all the widgets of the given association widget. */ void UMLScene::selectWidgetsOfAssoc(AssociationWidget * a) { if (a) { a->setSelected(true); //select the two widgets makeSelected(a->widgetForRole(Uml::RoleType::A)); makeSelected(a->widgetForRole(Uml::RoleType::B)); //select all the text makeSelected(a->multiplicityWidget(Uml::RoleType::A)); makeSelected(a->multiplicityWidget(Uml::RoleType::B)); makeSelected(a->roleWidget(Uml::RoleType::A)); makeSelected(a->roleWidget(Uml::RoleType::B)); makeSelected(a->changeabilityWidget(Uml::RoleType::A)); makeSelected(a->changeabilityWidget(Uml::RoleType::B)); } } /** * Selects all the widgets within an internally kept rectangle. */ void UMLScene::selectWidgets(qreal px, qreal py, qreal qx, qreal qy) { clearSelected(); QRectF rect; if (px <= qx) { rect.setLeft(px); rect.setRight(qx); } else { rect.setLeft(qx); rect.setRight(px); } if (py <= qy) { rect.setTop(py); rect.setBottom(qy); } else { rect.setTop(qy); rect.setBottom(py); } // Select UMLWidgets that fall within the selection rectangle foreach(UMLWidget* temp, widgetList()) { uIgnoreZeroPointer(temp); selectWidget(temp, &rect); } // Select messages that fall within the selection rectangle foreach(MessageWidget* temp, messageList()) { selectWidget(temp->asUMLWidget(), &rect); } // Select associations of selected widgets selectAssociations(true); // Automatically select all messages if two object widgets are selected foreach(MessageWidget *w, messageList()) { if (w->objectWidget(Uml::RoleType::A) && w->objectWidget(Uml::RoleType::B) && w->objectWidget(Uml::RoleType::A)->isSelected() && w->objectWidget(Uml::RoleType::B)->isSelected()) { makeSelected(w); } } } /** * Select a single widget * * If QRectF* rect is provided, the selection is only made if the widget is * visible within the rectangle. */ void UMLScene::selectWidget(UMLWidget* widget, QRectF* rect) { if (rect == 0) { makeSelected(widget); return; } int x = widget->x(); int y = widget->y(); int w = widget->width(); int h = widget->height(); QRectF rect2(x, y, w, h); //see if any part of widget is in the rectangle if (!rect->intersects(rect2)) { return; } //if it is text that is part of an association then select the association //and the objects that are connected to it. if (widget->isTextWidget()) { FloatingTextWidget *ft = widget->asFloatingTextWidget(); Uml::TextRole::Enum t = ft->textRole(); LinkWidget *lw = ft->link(); MessageWidget * mw = dynamic_cast(lw); if (mw) { makeSelected(mw); } else if (t != Uml::TextRole::Floating) { AssociationWidget * a = dynamic_cast(lw); if (a) selectWidgetsOfAssoc(a); } } else if (widget->isMessageWidget()) { MessageWidget *mw = widget->asMessageWidget(); makeSelected(mw); } if (widget->isVisible()) { makeSelected(widget); } } /** * Selects all the widgets from a list. */ void UMLScene::selectWidgets(UMLWidgetList &widgets) { foreach (UMLWidget* widget, widgets) makeSelected(widget); } /** * Returns the PNG picture of the paste operation. * @param diagram the class to store PNG picture of the paste operation. * @param rect the area of the diagram to copy */ void UMLScene::getDiagram(QPixmap &diagram, const QRectF &rect) { DEBUG(DBG_SRC) << "rect=" << rect << ", pixmap=" << diagram.rect(); QPainter painter(&diagram); painter.fillRect(0, 0, rect.width(), rect.height(), Qt::white); getDiagram(painter, rect); } /** * Paint diagram to the paint device * @param painter the QPainter to which the diagram is painted * @param source the area of the diagram to copy * @param target the rect where to paint into */ void UMLScene::getDiagram(QPainter &painter, const QRectF &source, const QRectF &target) { DEBUG(DBG_SRC) << "painter=" << painter.window() << ", source=" << source << ", target=" << target; //TODO unselecting and selecting later doesn't work now as the selection is //cleared in UMLSceneImageExporter. Check if the anything else than the //following is needed and, if it works, remove the clearSelected in //UMLSceneImageExporter and UMLSceneImageExporterModel UMLWidgetList selected = selectedWidgets(); foreach(UMLWidget* widget, selected) { widget->setSelected(false); } AssociationWidgetList selectedAssociationsList = selectedAssocs(); foreach(AssociationWidget* association, selectedAssociationsList) { association->setSelected(false); } // we don't want to get the grid bool showSnapGrid = isSnapGridVisible(); setSnapGridVisible(false); const int sourceMargin = 1; QRectF alignedSource(source); alignedSource.adjust(-sourceMargin, -sourceMargin, sourceMargin, sourceMargin); uDebug() << "TODO: Check if this render method is identical to cavnas()->drawArea()"; // [PORT] render(&painter, target, alignedSource, Qt::KeepAspectRatio); setSnapGridVisible(showSnapGrid); //select again foreach(UMLWidget* widget, selected) { widget->setSelected(true); } foreach(AssociationWidget* association, selectedAssociationsList) { association->setSelected(true); } } /** * Returns the imageExporter used to export the view. * * @return The imageExporter used to export the view. */ UMLViewImageExporter* UMLScene::getImageExporter() { return m_pImageExporter; } /** * makes this view the active view by asking the document to show us */ void UMLScene::slotActivate() { m_doc->changeCurrentView(ID()); } /** * Activate all the objects and associations after a load from the clipboard */ void UMLScene::activate() { //Activate Regular widgets then activate messages foreach(UMLWidget* obj, widgetList()) { uIgnoreZeroPointer(obj); //If this UMLWidget is already activated or is a MessageWidget then skip it if (obj->isActivated() || obj->isMessageWidget()) { continue; } if (obj->activate()) { obj->setVisible(true); } else { removeItem(obj); delete obj; } }//end foreach //Activate Message widgets foreach(UMLWidget* obj, messageList()) { //If this MessageWidget is already activated then skip it if (obj->isActivated()) continue; obj->activate(m_doc->changeLog()); obj->setVisible(true); }//end foreach // Activate all association widgets foreach(AssociationWidget* aw, associationList()) { if (aw->activate()) { if (m_PastePoint.x() != 0) { int x = m_PastePoint.x() - m_Pos.x(); int y = m_PastePoint.y() - m_Pos.y(); aw->moveEntireAssoc(x, y); } } else { removeWidgetCmd(aw); delete aw; } } } /** * Return the amount of widgets selected. * * @param filterText When true, do NOT count floating text widgets that * belong to other widgets (i.e. only count TextRole::Floating.) * Default: Count all widgets. * @return Number of widgets selected. */ int UMLScene::selectedCount(bool filterText) const { if (!filterText) return selectedWidgets().count(); int counter = 0; foreach(UMLWidget* temp, selectedWidgets()) { if (temp->isTextWidget()) { const FloatingTextWidget *ft = static_cast(temp); if (ft->textRole() == TextRole::Floating) counter++; } else { counter++; } } return counter; } /** * Fills the List with all the selected widgets from the diagram * The list can be filled with all the selected widgets, or be filtered to prevent * text widgets other than tr_Floating to be append. * * @param filterText Don't append the text, unless their role is tr_Floating * @return The UMLWidgetList to fill. */ UMLWidgetList UMLScene::selectedWidgetsExt(bool filterText /*= true*/) { UMLWidgetList widgetList; foreach(UMLWidget* widgt, selectedWidgets()) { if (filterText && widgt->isTextWidget()) { FloatingTextWidget *ft = widgt->asFloatingTextWidget(); if (ft->textRole() == Uml::TextRole::Floating) widgetList.append(widgt); } else { widgetList.append(widgt); } } return widgetList; } /** * Returns a list with all the selected associations from the diagram */ AssociationWidgetList UMLScene::selectedAssocs() { AssociationWidgetList assocWidgetList; foreach(AssociationWidget* assocwidget, associationList()) { if (assocwidget->isSelected()) assocWidgetList.append(assocwidget); } return assocWidgetList; } /** * Adds a floating text widget to the view */ void UMLScene::addFloatingTextWidget(FloatingTextWidget* pWidget) { int wX = pWidget->x(); int wY = pWidget->y(); bool xIsOutOfRange = (wX < sceneRect().left() || wX > sceneRect().right()); bool yIsOutOfRange = (wY < sceneRect().top() || wY > sceneRect().bottom()); if (xIsOutOfRange || yIsOutOfRange) { QString name = pWidget->name(); if (name.isEmpty()) { FloatingTextWidget *ft = pWidget->asFloatingTextWidget(); if (ft) name = ft->displayText(); } DEBUG(DBG_SRC) << name << " type=" << pWidget->baseTypeStr() << ": position (" << wX << "," << wY << ") is out of range"; if (xIsOutOfRange) { pWidget->setX(0); wX = 0; } if (yIsOutOfRange) { pWidget->setY(0); wY = 0; } } addWidgetCmd(pWidget); } /** * Adds an association to the view from the given data. * Use this method when pasting. */ bool UMLScene::addAssociation(AssociationWidget* pAssoc, bool isPasteOperation) { if (!pAssoc) { return false; } const Uml::AssociationType::Enum assocType = pAssoc->associationType(); if (isPasteOperation) { IDChangeLog * log = m_doc->changeLog(); if (!log) { return false; } Uml::ID::Type ida = Uml::ID::None, idb = Uml::ID::None; if (type() == DiagramType::Collaboration || type() == DiagramType::Sequence) { //check local log first ida = m_pIDChangesLog->findNewID(pAssoc->widgetIDForRole(Uml::RoleType::A)); idb = m_pIDChangesLog->findNewID(pAssoc->widgetIDForRole(Uml::RoleType::B)); //if either is still not found and assoc type is anchor //we are probably linking to a notewidet - else an error if (ida == Uml::ID::None && assocType == Uml::AssociationType::Anchor) ida = log->findNewID(pAssoc->widgetIDForRole(Uml::RoleType::A)); if (idb == Uml::ID::None && assocType == Uml::AssociationType::Anchor) idb = log->findNewID(pAssoc->widgetIDForRole(Uml::RoleType::B)); } else { Uml::ID::Type oldIdA = pAssoc->widgetIDForRole(Uml::RoleType::A); Uml::ID::Type oldIdB = pAssoc->widgetIDForRole(Uml::RoleType::B); ida = log->findNewID(oldIdA); if (ida == Uml::ID::None) { // happens after a cut if (oldIdA == Uml::ID::None) { return false; } ida = oldIdA; } idb = log->findNewID(oldIdB); if (idb == Uml::ID::None) { // happens after a cut if (oldIdB == Uml::ID::None) { return false; } idb = oldIdB; } } if (ida == Uml::ID::None || idb == Uml::ID::None) { return false; } // cant do this anymore.. may cause problem for pasting // pAssoc->setWidgetID(ida, A); // pAssoc->setWidgetID(idb, B); pAssoc->setWidgetForRole(findWidget(ida), Uml::RoleType::A); pAssoc->setWidgetForRole(findWidget(idb), Uml::RoleType::B); } UMLWidget * pWidgetA = findWidget(pAssoc->widgetIDForRole(Uml::RoleType::A)); UMLWidget * pWidgetB = findWidget(pAssoc->widgetIDForRole(Uml::RoleType::B)); //make sure valid widget ids if (!pWidgetA || !pWidgetB) { return false; } //make sure there isn't already the same assoc foreach(AssociationWidget* assocwidget, associationList()) { if (*pAssoc == *assocwidget) // this is nuts. Paste operation wants to know if 'true' // for duplicate, but loadFromXMI1 needs 'false' value return (isPasteOperation ? true : false); } addWidgetCmd(pAssoc); FloatingTextWidget *ft[5] = { pAssoc->nameWidget(), pAssoc->roleWidget(Uml::RoleType::A), pAssoc->roleWidget(Uml::RoleType::B), pAssoc->multiplicityWidget(Uml::RoleType::A), pAssoc->multiplicityWidget(Uml::RoleType::B) }; for (int i = 0; i < 5; i++) { FloatingTextWidget *flotxt = ft[i]; if (flotxt) { flotxt->updateGeometry(); addFloatingTextWidget(flotxt); } } return true; } /** * Activate the view after a load a new file */ void UMLScene::activateAfterLoad(bool bUseLog) { if (m_isActivated) { return; } if (bUseLog) { beginPartialWidgetPaste(); } //now activate them all activate(); if (bUseLog) { endPartialWidgetPaste(); } m_view->centerOn(0, 0); m_isActivated = true; } void UMLScene::beginPartialWidgetPaste() { delete m_pIDChangesLog; m_pIDChangesLog = 0; m_pIDChangesLog = new IDChangeLog(); m_bPaste = true; } void UMLScene::endPartialWidgetPaste() { delete m_pIDChangesLog; m_pIDChangesLog = 0; m_bPaste = false; } /** * Removes a AssociationWidget from a diagram * Physically deletes the AssociationWidget passed in. * * @param pAssoc Pointer to the AssociationWidget. */ void UMLScene::removeWidgetCmd(AssociationWidget* pAssoc) { if (!pAssoc) return; emit sigAssociationRemoved(pAssoc); pAssoc->cleanup(); removeItem(pAssoc); pAssoc->deleteLater(); m_doc->setModified(); } /** * Removes an AssociationWidget from the association list * and removes the corresponding UMLAssociation from the current UMLDoc. */ void UMLScene::removeAssocInViewAndDoc(AssociationWidget* a) { // For umbrello 1.2, UMLAssociations can only be removed in two ways: // 1. Right click on the assocwidget in the view and select Delete // 2. Go to the Class Properties page, select Associations, right click // on the association and select Delete if (!a) return; if (a->associationType() == Uml::AssociationType::Containment) { UMLObject *objToBeMoved = a->widgetForRole(Uml::RoleType::B)->umlObject(); if (objToBeMoved != 0) { UMLListView *lv = UMLApp::app()->listView(); lv->moveObject(objToBeMoved->id(), Model_Utils::convert_OT_LVT(objToBeMoved), lv->theLogicalView()); // UMLListView::moveObject() will delete the containment // AssociationWidget via UMLScene::updateContainment(). } else { DEBUG(DBG_SRC) << "removeAssocInViewAndDoc(containment): " << "objB is NULL"; } } else { // Remove assoc in doc. m_doc->removeAssociation(a->association()); // Remove assoc in view. removeWidgetCmd(a); } } /** * Removes all the associations related to Widget. * * @param widget Pointer to the widget to remove. */ void UMLScene::removeAssociations(UMLWidget* widget) { foreach(AssociationWidget* assocwidget, associationList()) { if (assocwidget->containsAsEndpoint(widget)) { removeWidgetCmd(assocwidget); } } } /** * Sets each association as selected if the widgets it associates are selected * * @param bSelect True to select, false for unselect */ void UMLScene::selectAssociations(bool bSelect) { foreach(AssociationWidget* assocwidget, associationList()) { UMLWidget *widA = assocwidget->widgetForRole(Uml::RoleType::A); UMLWidget *widB = assocwidget->widgetForRole(Uml::RoleType::B); if (bSelect && widA && widA->isSelected() && widB && widB->isSelected()) { assocwidget->setSelected(true); } else { assocwidget->setSelected(false); } } } /** * Fills Associations with all the associations that includes a widget related to object */ void UMLScene::getWidgetAssocs(UMLObject* Obj, AssociationWidgetList & Associations) { if (! Obj) return; foreach(AssociationWidget* assocwidget, associationList()) { if (assocwidget->widgetForRole(Uml::RoleType::A)->umlObject() == Obj || assocwidget->widgetForRole(Uml::RoleType::B)->umlObject() == Obj) Associations.append(assocwidget); } } /** * Removes All the associations of the diagram */ void UMLScene::removeAllAssociations() { //Remove All association widgets foreach(AssociationWidget* assocwidget, associationList()) { removeWidgetCmd(assocwidget); } } /** * Removes All the widgets of the diagram */ void UMLScene::removeAllWidgets() { // Remove widgets. foreach(UMLWidget* temp, widgetList()) { uIgnoreZeroPointer(temp); // I had to take this condition back in, else umbrello // crashes on exit. Still to be analyzed. --okellogg if (!(temp->isTextWidget() && temp->asFloatingTextWidget()->textRole() != TextRole::Floating)) { removeWidgetCmd(temp); } } } /** * Refreshes containment association, i.e. removes possible old * containment and adds new containment association if applicable. * * @param self Pointer to the contained object for which * the association to the containing object is * recomputed. */ void UMLScene::updateContainment(UMLCanvasObject *self) { if (self == 0) return; // See if the object has a widget representation in this view. // While we're at it, also see if the new parent has a widget here. UMLWidget *selfWidget = 0, *newParentWidget = 0; UMLPackage *newParent = self->umlPackage(); foreach(UMLWidget* w, widgetList()) { UMLObject *o = w->umlObject(); if (o == self) selfWidget = w; else if (newParent != 0 && o == newParent) newParentWidget = w; } if (selfWidget == 0) return; // Remove possibly obsoleted containment association. foreach(AssociationWidget* a, associationList()) { if (a->associationType() != Uml::AssociationType::Containment) continue; // Container is at role A, containee at B. // We only look at association for which we are B. UMLWidget *wB = a->widgetForRole(Uml::RoleType::B); UMLObject *roleBObj = wB->umlObject(); if (roleBObj != self) continue; UMLWidget *wA = a->widgetForRole(Uml::RoleType::A); UMLObject *roleAObj = wA->umlObject(); if (roleAObj == newParent) { // Wow, all done. Great! return; } removeWidgetCmd(a); // It's okay to break out because there can only be a single // containing object. break; } if (newParentWidget == 0) return; // Create the new containment association. AssociationWidget *a = AssociationWidget::create (this, newParentWidget, Uml::AssociationType::Containment, selfWidget); addWidgetCmd(a); } /** * Creates automatically any Associations that the given @ref UMLWidget * may have on any diagram. This method is used when you just add the UMLWidget * to a diagram. */ void UMLScene::createAutoAssociations(UMLWidget * widget) { if (widget == 0 || (m_Type != Uml::DiagramType::Class && m_Type != Uml::DiagramType::Object && m_Type != Uml::DiagramType::Component && m_Type != Uml::DiagramType::Deployment && m_Type != Uml::DiagramType::EntityRelationship)) return; // Recipe: // If this widget has an underlying UMLCanvasObject then // for each of the UMLCanvasObject's UMLAssociations // if umlassoc's "other" role has a widget representation on this view then // if the AssocWidget does not already exist then // if the assoc type is permitted in the current diagram type then // create the AssocWidget // end if // end if // end if // end loop // Do createAutoAttributeAssociations() // if this object is capable of containing nested objects then // for each of the object's containedObjects // if the containedObject has a widget representation on this view then // if the containedWidget is not physically located inside this widget // create the containment AssocWidget // end if // end if // end loop // end if // if the UMLCanvasObject has a parentPackage then // if the parentPackage has a widget representation on this view then // create the containment AssocWidget // end if // end if // end if UMLObject *tmpUmlObj = widget->umlObject(); if (tmpUmlObj == 0) return; UMLCanvasObject *umlObj = tmpUmlObj->asUMLCanvasObject(); if (umlObj == 0) return; const UMLAssociationList& umlAssocs = umlObj->getAssociations(); Uml::ID::Type myID = umlObj->id(); foreach(UMLAssociation* assoc, umlAssocs) { UMLCanvasObject *other = 0; UMLObject *roleAObj = assoc->getObject(Uml::RoleType::A); if (roleAObj == 0) { DEBUG(DBG_SRC) << "roleA object is NULL at UMLAssoc " << Uml::ID::toString(assoc->id()); continue; } UMLObject *roleBObj = assoc->getObject(Uml::RoleType::B); if (roleBObj == 0) { DEBUG(DBG_SRC) << "roleB object is NULL at UMLAssoc " << Uml::ID::toString(assoc->id()); continue; } if (roleAObj->id() == myID) { other = roleBObj->asUMLCanvasObject(); } else if (roleBObj->id() == myID) { other = roleAObj->asUMLCanvasObject(); } else { DEBUG(DBG_SRC) << "Cannot find own object " << Uml::ID::toString(myID) << " in UMLAssoc " << Uml::ID::toString(assoc->id()); continue; } // Now that we have determined the "other" UMLObject, seek it in // this view's UMLWidgets. if (!other) { continue; } Uml::ID::Type otherID = other->id(); bool breakFlag = false; UMLWidget* pOtherWidget = 0; foreach(pOtherWidget, widgetList()) { if (pOtherWidget->id() == otherID) { breakFlag = true; break; } } if (!breakFlag) continue; // Both objects are represented in this view: // Assign widget roles as indicated by the UMLAssociation. UMLWidget *widgetA, *widgetB; if (myID == roleAObj->id()) { widgetA = widget; widgetB = pOtherWidget; } else { widgetA = pOtherWidget; widgetB = widget; } // Check that the assocwidget does not already exist. Uml::AssociationType::Enum assocType = assoc->getAssocType(); AssociationWidget * assocwidget = findAssocWidget(assocType, widgetA, widgetB); if (assocwidget) { assocwidget->calculateEndingPoints(); // recompute assoc lines continue; } // Check that the assoc is allowed. if (!AssocRules::allowAssociation(assocType, widgetA, widgetB)) { DEBUG(DBG_SRC) << "not transferring assoc " << "of type " << assocType; continue; } // Create the AssociationWidget. assocwidget = AssociationWidget::create(this); assocwidget->setWidgetForRole(widgetA, Uml::RoleType::A); assocwidget->setWidgetForRole(widgetB, Uml::RoleType::B); assocwidget->setAssociationType(assocType); assocwidget->setUMLObject(assoc); // Call calculateEndingPoints() before setting the FloatingTexts // because their positions are computed according to the // assocwidget line positions. assocwidget->calculateEndingPoints(); assocwidget->syncToModel(); assocwidget->setActivated(true); if (! addAssociation(assocwidget)) delete assocwidget; } createAutoAttributeAssociations(widget); if (m_Type == Uml::DiagramType::EntityRelationship) { createAutoConstraintAssociations(widget); } // if this object is capable of containing nested objects then UMLObject::ObjectType t = umlObj->baseType(); if (t == UMLObject::ot_Package || t == UMLObject::ot_Class || t == UMLObject::ot_Interface || t == UMLObject::ot_Component) { // for each of the object's containedObjects UMLPackage *umlPkg = umlObj->asUMLPackage(); UMLObjectList lst = umlPkg->containedObjects(); foreach(UMLObject* obj, lst) { uIgnoreZeroPointer(obj); // if the containedObject has a widget representation on this view then Uml::ID::Type id = obj->id(); foreach(UMLWidget *w, widgetList()) { uIgnoreZeroPointer(w); if (w->id() != id) continue; // if the containedWidget is not physically located inside this widget if (widget->rect().contains(w->rect())) continue; // create the containment AssocWidget AssociationWidget *a = AssociationWidget::create(this, widget, Uml::AssociationType::Containment, w); a->calculateEndingPoints(); a->setActivated(true); if (! addAssociation(a)) delete a; } } } // if the UMLCanvasObject has a parentPackage then UMLPackage *parent = umlObj->umlPackage(); if (parent == 0) return; // if the parentPackage has a widget representation on this view then Uml::ID::Type pkgID = parent->id(); bool breakFlag = false; UMLWidget* pWidget = 0; foreach(pWidget, widgetList()) { uIgnoreZeroPointer(pWidget); if (pWidget->id() == pkgID) { breakFlag = true; break; } } if (!breakFlag || pWidget->rect().contains(widget->rect())) return; // create the containment AssocWidget AssociationWidget *a = AssociationWidget::create(this, pWidget, Uml::AssociationType::Containment, widget); if (! addAssociation(a)) delete a; } /** * If the m_Type of the given widget is WidgetBase::wt_Class then * iterate through the class' attributes and create an * association to each attribute type widget that is present * on the current diagram. */ void UMLScene::createAutoAttributeAssociations(UMLWidget *widget) { if (widget == 0 || m_Type != Uml::DiagramType::Class || !m_Options.classState.showAttribAssocs) return; // Pseudocode: // if the underlying model object is really a UMLClassifier then // for each of the UMLClassifier's UMLAttributes // if the attribute type has a widget representation on this view then // if the AssocWidget does not already exist then // if the current diagram type permits compositions then // create a composition AssocWidget // end if // end if // end if // if the attribute type is a Datatype then // if the Datatype is a reference (pointer) type then // if the referenced type has a widget representation on this view then // if the AssocWidget does not already exist then // if the current diagram type permits aggregations then // create an aggregation AssocWidget from the ClassifierWidget to the // widget of the referenced type // end if // end if // end if // end if // end if // end loop // end if // // Implementation: UMLObject *tmpUmlObj = widget->umlObject(); if (tmpUmlObj == 0) return; // if the underlying model object is really a UMLClassifier then if (tmpUmlObj->isUMLDatatype()) { UMLDatatype *dt = tmpUmlObj->asUMLDatatype(); while (dt && dt->originType() != 0) { tmpUmlObj = dt->originType(); if (!tmpUmlObj->isUMLDatatype()) break; dt = tmpUmlObj->asUMLDatatype(); } } if (tmpUmlObj->baseType() != UMLObject::ot_Class) return; UMLClassifier * klass = tmpUmlObj->asUMLClassifier(); // for each of the UMLClassifier's UMLAttributes UMLAttributeList attrList = klass->getAttributeList(); foreach(UMLAttribute* attr, attrList) { createAutoAttributeAssociation(attr->getType(), attr, widget); /* * The following code from attachment 19935 of http://bugs.kde.org/140669 * creates Aggregation/Composition to the template parameters. * The current solution uses Dependency instead, see handling of template * instantiation at Import_Utils::createUMLObject(). UMLClassifierList templateList = attr->getTemplateParams(); for (UMLClassifierListIt it(templateList); it.current(); ++it) { createAutoAttributeAssociation(it, attr, widget); } */ } } /** * Create an association with the attribute attr associated with the UMLWidget * widget if the UMLClassifier type is present on the current diagram. */ void UMLScene::createAutoAttributeAssociation(UMLClassifier *type, UMLAttribute *attr, UMLWidget *widget /*, UMLClassifier * klass*/) { if (type == 0) { // DEBUG(DBG_SRC) << klass->getName() << ": type is NULL for " // << "attribute " << attr->getName(); return; } Uml::AssociationType::Enum assocType = Uml::AssociationType::Composition; UMLWidget *w = findWidget(type->id()); // if the attribute type has a widget representation on this view if (w) { AssociationWidget *a = findAssocWidget(widget, w, attr->name()); if (a == 0 && // if the current diagram type permits compositions AssocRules::allowAssociation(assocType, widget, w)) { // Create a composition AssocWidget, or, if the attribute type is // stereotyped <>, create a UniAssociation widget. if (type->stereotype() == QLatin1String("CORBAInterface")) assocType = Uml::AssociationType::UniAssociation; a = AssociationWidget::create(this, widget, assocType, w, attr); a->setVisibility(attr->visibility(), Uml::RoleType::B); /* if (assocType == Uml::AssociationType::Aggregation || assocType == Uml::AssociationType::UniAssociation) a->setMulti("0..1", Uml::RoleType::B); */ a->setRoleName(attr->name(), Uml::RoleType::B); a->setActivated(true); if (! addAssociation(a)) delete a; } } // if the attribute type is a Datatype then if (type->isUMLDatatype()) { UMLDatatype *dt = type->asUMLDatatype(); // if the Datatype is a reference (pointer) type if (dt && dt->isReference()) { //Uml::AssociationType::Enum assocType = Uml::AssociationType::Composition; UMLClassifier *c = dt->originType(); UMLWidget *w = c ? findWidget(c->id()) : 0; // if the referenced type has a widget representation on this view if (w) { AssociationWidget *a = findAssocWidget(widget, w, attr->name()); if (a == 0 && // if the current diagram type permits aggregations AssocRules::allowAssociation(Uml::AssociationType::Aggregation, widget, w)) { // create an aggregation AssocWidget from the ClassifierWidget // to the widget of the referenced type a = AssociationWidget::create (this, widget, Uml::AssociationType::Aggregation, w, attr); a->setVisibility(attr->visibility(), Uml::RoleType::B); //a->setChangeability(true, Uml::RoleType::B); a->setMultiplicity(QLatin1String("0..1"), Uml::RoleType::B); a->setRoleName(attr->name(), Uml::RoleType::B); a->setActivated(true); if (! addAssociation(a)) delete a; } } } } } void UMLScene::createAutoConstraintAssociations(UMLWidget *widget) { if (widget == 0 || m_Type != Uml::DiagramType::EntityRelationship) return; // Pseudocode: // if the underlying model object is really a UMLEntity then // for each of the UMLEntity's UMLForeignKeyConstraint's // if the attribute type has a widget representation on this view then // if the AssocWidget does not already exist then // if the current diagram type permits relationships then // create a relationship AssocWidget // end if // end if // end if UMLObject *tmpUmlObj = widget->umlObject(); if (tmpUmlObj == 0) return; // check if the underlying model object is really a UMLEntity UMLCanvasObject *umlObj = tmpUmlObj->asUMLCanvasObject(); if (umlObj == 0) return; // finished checking whether this widget has a UMLCanvas Object if (tmpUmlObj->baseType() != UMLObject::ot_Entity) return; UMLEntity *entity = tmpUmlObj->asUMLEntity(); // for each of the UMLEntity's UMLForeignKeyConstraints UMLClassifierListItemList constrList = entity->getFilteredList(UMLObject::ot_ForeignKeyConstraint); foreach(UMLClassifierListItem* cli, constrList) { UMLEntityConstraint *eConstr = cli->asUMLEntityConstraint(); UMLForeignKeyConstraint* fkc = eConstr->asUMLForeignKeyConstraint(); if (fkc == 0) { return; } UMLEntity* refEntity = fkc->getReferencedEntity(); if (refEntity == 0) { return; } createAutoConstraintAssociation(refEntity, fkc, widget); } } void UMLScene::createAutoConstraintAssociation(UMLEntity* refEntity, UMLForeignKeyConstraint* fkConstraint, UMLWidget* widget) { if (refEntity == 0) { return; } Uml::AssociationType::Enum assocType = Uml::AssociationType::Relationship; UMLWidget *w = findWidget(refEntity->id()); AssociationWidget *aw = 0; if (w) { aw = findAssocWidget(w, widget, fkConstraint->name()); if (aw == 0 && // if the current diagram type permits relationships AssocRules::allowAssociation(assocType, w, widget)) { // for foreign key contstraint, we need to create the association type Uml::AssociationType::Relationship. // The referenced entity is the "1" part (Role A) and the entity holding the relationship is the "many" part. (Role B) AssociationWidget *a = AssociationWidget::create(this, w, assocType, widget); a->setUMLObject(fkConstraint); //a->setVisibility(attr->getVisibility(), Uml::RoleType::B); a->setRoleName(fkConstraint->name(), Uml::RoleType::B); a->setActivated(true); if (! addAssociation(a)) delete a; } } } void UMLScene::createAutoAttributeAssociations2(UMLWidget *widget) { foreach(UMLWidget* w, widgetList()) { uIgnoreZeroPointer(w); if (w != widget) { createAutoAttributeAssociations(w); if (widget->umlObject() && widget->umlObject()->baseType() == UMLObject::ot_Entity) createAutoConstraintAssociations(w); } } } /** * Find the maximum bounding rectangle of FloatingTextWidget widgets. * Auxiliary to copyAsImage(). * * @param ft Pointer to the FloatingTextWidget widget to consider. * @param px X coordinate of lower left corner. This value will be * updated if the X coordinate of the lower left corner * of ft is smaller than the px value passed in. * @param py Y coordinate of lower left corner. This value will be * updated if the Y coordinate of the lower left corner * of ft is smaller than the py value passed in. * @param qx X coordinate of upper right corner. This value will be * updated if the X coordinate of the upper right corner * of ft is larger than the qx value passed in. * @param qy Y coordinate of upper right corner. This value will be * updated if the Y coordinate of the upper right corner * of ft is larger than the qy value passed in. */ void UMLScene::findMaxBoundingRectangle(const FloatingTextWidget* ft, qreal& px, qreal& py, qreal& qx, qreal& qy) { if (ft == 0 || !ft->isVisible()) return; qreal x = ft->x(); qreal y = ft->y(); qreal x1 = x + ft->width() - 1; qreal y1 = y + ft->height() - 1; if (px == -1 || x < px) px = x; if (py == -1 || y < py) py = y; if (qx == -1 || x1 > qx) qx = x1; if (qy == -1 || y1 > qy) qy = y1; } /** * Returns the PNG picture of the paste operation. */ void UMLScene::copyAsImage(QPixmap*& pix) { //get the smallest rect holding the diagram QRectF rect = diagramRect(); QPixmap diagram(rect.width(), rect.height()); //only draw what is selected m_bDrawSelectedOnly = true; selectAssociations(true); getDiagram(diagram, rect); //now get the selection cut qreal px = -1, py = -1, qx = -1, qy = -1; //first get the smallest rect holding the widgets foreach(UMLWidget* temp, selectedWidgets()) { qreal x = temp->x(); qreal y = temp->y(); qreal x1 = x + temp->width() - 1; qreal y1 = y + temp->height() - 1; if (px == -1 || x < px) { px = x; } if (py == -1 || y < py) { py = y; } if (qx == -1 || x1 > qx) { qx = x1; } if (qy == -1 || y1 > qy) { qy = y1; } } //also take into account any text lines in assocs or messages //get each type of associations //This needs to be reimplemented to increase the rectangle //if a part of any association is not included foreach(AssociationWidget *a, associationList()) { if (! a->isSelected()) continue; const FloatingTextWidget* multiA = a->multiplicityWidget(Uml::RoleType::A); const FloatingTextWidget* multiB = a->multiplicityWidget(Uml::RoleType::B); const FloatingTextWidget* roleA = a->roleWidget(Uml::RoleType::A); const FloatingTextWidget* roleB = a->roleWidget(Uml::RoleType::B); const FloatingTextWidget* changeA = a->changeabilityWidget(Uml::RoleType::A); const FloatingTextWidget* changeB = a->changeabilityWidget(Uml::RoleType::B); findMaxBoundingRectangle(multiA, px, py, qx, qy); findMaxBoundingRectangle(multiB, px, py, qx, qy); findMaxBoundingRectangle(roleA, px, py, qx, qy); findMaxBoundingRectangle(roleB, px, py, qx, qy); findMaxBoundingRectangle(changeA, px, py, qx, qy); findMaxBoundingRectangle(changeB, px, py, qx, qy); }//end foreach QRectF imageRect; //area with respect to diagramRect() //i.e. all widgets on the scene. Was previously with //respect to whole scene imageRect.setLeft(px - rect.left()); imageRect.setTop(py - rect.top()); imageRect.setRight(qx - rect.left()); imageRect.setBottom(qy - rect.top()); pix = new QPixmap(imageRect.width(), imageRect.height()); QPainter output(pix); output.drawPixmap(QPoint(0, 0), diagram, imageRect); m_bDrawSelectedOnly = false; } /** * Reset the toolbar. */ void UMLScene::resetToolbar() { emit sigResetToolBar(); } /** * Event handler for context menu events. */ void UMLScene::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) { QGraphicsScene::contextMenuEvent(event); if (!event->isAccepted()) { setPos(event->scenePos()); UMLScenePopupMenu popup(m_view, this); QAction *triggered = popup.exec(event->screenPos()); slotMenuSelection(triggered); event->accept(); } } /** * Returns the status on whether in a paste state. * * @return Returns the status on whether in a paste state. */ bool UMLScene::getPaste() const { return m_bPaste; } /** * Sets the status on whether in a paste state. */ void UMLScene::setPaste(bool paste) { m_bPaste = paste; } /** * When a menu selection has been made on the menu * that this view created, this method gets called. */ void UMLScene::slotMenuSelection(QAction* action) { ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(action); switch (sel) { case ListPopupMenu::mt_Undo: UMLApp::app()->undo(); break; case ListPopupMenu::mt_Redo: UMLApp::app()->redo(); break; case ListPopupMenu::mt_Clear: clearDiagram(); break; case ListPopupMenu::mt_Export_Image: m_pImageExporter->exportView(); break; case ListPopupMenu::mt_Apply_Layout: case ListPopupMenu::mt_Apply_Layout1: case ListPopupMenu::mt_Apply_Layout2: case ListPopupMenu::mt_Apply_Layout3: case ListPopupMenu::mt_Apply_Layout4: case ListPopupMenu::mt_Apply_Layout5: case ListPopupMenu::mt_Apply_Layout6: case ListPopupMenu::mt_Apply_Layout7: case ListPopupMenu::mt_Apply_Layout8: case ListPopupMenu::mt_Apply_Layout9: { QVariant value = ListPopupMenu::dataFromAction(ListPopupMenu::dt_ApplyLayout, action); applyLayout(value.toString()); } break; case ListPopupMenu::mt_FloatText: { FloatingTextWidget* ft = new FloatingTextWidget(this); ft->showChangeTextDialog(); //if no text entered delete if (!FloatingTextWidget::isTextValid(ft->text())) { delete ft; } else { ft->setID(UniqueID::gen()); setupNewWidget(ft); } } break; case ListPopupMenu::mt_UseCase: m_bCreateObject = true; Object_Factory::createUMLObject(UMLObject::ot_UseCase); break; case ListPopupMenu::mt_Actor: m_bCreateObject = true; Object_Factory::createUMLObject(UMLObject::ot_Actor); break; case ListPopupMenu::mt_Class: case ListPopupMenu::mt_Object: m_bCreateObject = true; Object_Factory::createUMLObject(UMLObject::ot_Class); break; case ListPopupMenu::mt_Package: m_bCreateObject = true; Object_Factory::createUMLObject(UMLObject::ot_Package); break; case ListPopupMenu::mt_Subsystem: { m_bCreateObject = true; UMLPackage *component = UMLApp::app()->document()->rootFolder(Uml::ModelType::Component); QString name = Model_Utils::uniqObjectName(UMLObject::ot_Package, component, i18n("new_subsystem")); if (Dialog_Utils::askName(i18n("Enter Subsystem Name"), i18n("Enter the name of the new subsystem"), name)) { UMLObject *package = Object_Factory::createUMLObject(UMLObject::ot_Package, name, component); if (package) package->setStereotypeCmd(QLatin1String("subsystem")); } break; } case ListPopupMenu::mt_Component: m_bCreateObject = true; Object_Factory::createUMLObject(UMLObject::ot_Component); break; case ListPopupMenu::mt_Node: m_bCreateObject = true; Object_Factory::createUMLObject(UMLObject::ot_Node); break; case ListPopupMenu::mt_Artifact: m_bCreateObject = true; Object_Factory::createUMLObject(UMLObject::ot_Artifact); break; case ListPopupMenu::mt_Interface: m_bCreateObject = true; Object_Factory::createUMLObject(UMLObject::ot_Interface); break; case ListPopupMenu::mt_Enum: m_bCreateObject = true; Object_Factory::createUMLObject(UMLObject::ot_Enum); break; case ListPopupMenu::mt_Entity: m_bCreateObject = true; Object_Factory::createUMLObject(UMLObject::ot_Entity); break; case ListPopupMenu::mt_Category: m_bCreateObject = true; Object_Factory::createUMLObject(UMLObject::ot_Category); break; case ListPopupMenu::mt_Datatype: m_bCreateObject = true; Object_Factory::createUMLObject(UMLObject::ot_Datatype); break; case ListPopupMenu::mt_Instance: m_bCreateObject = true; Object_Factory::createUMLObject(UMLObject::ot_Instance); break; case ListPopupMenu::mt_Note: { m_bCreateObject = true; UMLWidget* widget = new NoteWidget(this); addItem(widget); widget->setPos(pos()); widget->setSize(100, 40); widget->showPropertiesDialog(); QSizeF size = widget->minimumSize(); widget->setSize(size); break; } case ListPopupMenu::mt_Cut: //FIXME make this work for diagram's right click menu if (selectedWidgets().count() && UMLApp::app()->editCutCopy(true)) { deleteSelection(); m_doc->setModified(true); } break; case ListPopupMenu::mt_Copy: //FIXME make this work for diagram's right click menu selectedWidgets().count() && UMLApp::app()->editCutCopy(true); break; case ListPopupMenu::mt_Paste: m_PastePoint = m_Pos; m_Pos.setX(2000); m_Pos.setY(2000); UMLApp::app()->slotEditPaste(); m_PastePoint.setX(0); m_PastePoint.setY(0); break; case ListPopupMenu::mt_Initial_State: { StateWidget* state = new StateWidget(this, StateWidget::Initial); setupNewWidget(state); } break; case ListPopupMenu::mt_End_State: { StateWidget* state = new StateWidget(this, StateWidget::End); setupNewWidget(state); } break; case ListPopupMenu::mt_Junction: { StateWidget* state = new StateWidget(this, StateWidget::Junction); setupNewWidget(state); } break; case ListPopupMenu::mt_DeepHistory: { StateWidget* state = new StateWidget(this, StateWidget::DeepHistory); setupNewWidget(state); } break; case ListPopupMenu::mt_ShallowHistory: { StateWidget* state = new StateWidget(this, StateWidget::ShallowHistory); setupNewWidget(state); } break; case ListPopupMenu::mt_Choice: { StateWidget* state = new StateWidget(this, StateWidget::Choice); setupNewWidget(state); } break; case ListPopupMenu::mt_StateFork: { StateWidget* state = new StateWidget(this, StateWidget::Fork); setupNewWidget(state); } break; case ListPopupMenu::mt_StateJoin: { StateWidget* state = new StateWidget(this, StateWidget::Join); setupNewWidget(state); } break; case ListPopupMenu::mt_State: { QString name = i18n("new state"); bool ok = Dialog_Utils::askName(i18n("Enter State Name"), i18n("Enter the name of the new state:"), name); if (ok) { StateWidget* state = new StateWidget(this); state->setName(name); setupNewWidget(state); } } break; case ListPopupMenu::mt_Initial_Activity: { ActivityWidget* activity = new ActivityWidget(this, ActivityWidget::Initial); setupNewWidget(activity); } break; case ListPopupMenu::mt_End_Activity: { ActivityWidget* activity = new ActivityWidget(this, ActivityWidget::End); setupNewWidget(activity); } break; case ListPopupMenu::mt_Branch: { ActivityWidget* activity = new ActivityWidget(this, ActivityWidget::Branch); setupNewWidget(activity); } break; case ListPopupMenu::mt_Activity: { QString name = i18n("new activity"); bool ok = Dialog_Utils::askName(i18n("Enter Activity Name"), i18n("Enter the name of the new activity:"), name); if (ok) { ActivityWidget* activity = new ActivityWidget(this, ActivityWidget::Normal); activity->setName(name); setupNewWidget(activity); } } break; case ListPopupMenu::mt_SnapToGrid: toggleSnapToGrid(); m_doc->setModified(); break; case ListPopupMenu::mt_SnapComponentSizeToGrid: toggleSnapComponentSizeToGrid(); m_doc->setModified(); break; case ListPopupMenu::mt_ShowSnapGrid: toggleShowGrid(); m_doc->setModified(); break; case ListPopupMenu::mt_ShowDocumentationIndicator: setShowDocumentationIndicator(!isShowDocumentationIndicator()); update(); break; case ListPopupMenu::mt_Properties: if (m_view->showPropertiesDialog() == true) m_doc->setModified(); break; case ListPopupMenu::mt_Delete: m_doc->removeDiagram(ID()); break; case ListPopupMenu::mt_Rename: { QString newName = name(); bool ok = Dialog_Utils::askName(i18n("Enter Diagram Name"), i18n("Enter the new name of the diagram:"), newName); if (ok) { setName(newName); m_doc->signalDiagramRenamed(activeView()); } } break; case ListPopupMenu::mt_Import_from_File: { QPointer dialog = new UMLFileDialog(QUrl(), QString(), UMLApp::app()); dialog->exec(); QUrl url = dialog->selectedUrl(); if (!url.isEmpty()) if (!Diagram_Utils::importGraph(url.toLocalFile(), this)) UMLApp::app()->slotStatusMsg(i18n("Failed to import from file.")); break; } default: uWarning() << "unknown ListPopupMenu::MenuType " << ListPopupMenu::toString(sel); break; } } /** * Connects to the signal that @ref UMLApp emits when a cut operation * is successful. * If the view or a child started the operation the flag m_bStartedCut will * be set and we can carry out any operation that is needed, like deleting the selected * widgets for the cut operation. */ void UMLScene::slotCutSuccessful() { if (m_bStartedCut) { deleteSelection(); m_bStartedCut = false; } } /** * Called by menu when to show the instance of the view. */ void UMLScene::slotShowView() { m_doc->changeCurrentView(ID()); } /** * Returns the offset point at which to place the paste from clipboard. * Just add the amount to your co-ords. * Only call this straight after the event, the value won't stay valid. * Should only be called by Assoc widgets at the moment. no one else needs it. */ QPointF UMLScene::getPastePoint() { QPointF point = m_PastePoint; point.setX(point.x() - m_Pos.x()); point.setY(point.y() - m_Pos.y()); return point; } /** * Reset the paste point. */ void UMLScene::resetPastePoint() { m_PastePoint = m_Pos; } /** * Called by the view or any of its children when they start a cut * operation. */ void UMLScene::setStartedCut() { m_bStartedCut = true; } /** * Returns the font to use */ QFont UMLScene::font() const { return m_Options.uiState.font; } /** * Sets the font for the view and optionally all the widgets on the view. */ void UMLScene::setFont(QFont font, bool changeAllWidgets /* = false */) { m_Options.uiState.font = font; if (!changeAllWidgets) return; foreach(UMLWidget* w, widgetList()) { uIgnoreZeroPointer(w); w->setFont(font); } } /** * Sets some options for all the @ref ClassifierWidget on the view. */ void UMLScene::setClassWidgetOptions(ClassOptionsPage * page) { foreach(UMLWidget* pWidget, widgetList()) { uIgnoreZeroPointer(pWidget); WidgetBase::WidgetType wt = pWidget->baseType(); - if (wt == WidgetBase::wt_Class || wt == WidgetBase::wt_Interface) { - page->setWidget(static_cast(pWidget)); + if (wt == WidgetBase::wt_Class) { + page->setWidget(pWidget->asClassifierWidget()); + page->apply(); + } else if (wt == WidgetBase::wt_Interface) { + page->setWidget(pWidget->asInterfaceWidget()); page->apply(); } } } /** * Returns the type of the selected widget or widgets. * * If multiple widgets of different types are selected. WidgetType::UMLWidget * is returned. */ WidgetBase::WidgetType UMLScene::getUniqueSelectionType() { if (selectedWidgets().isEmpty()) { return WidgetBase::wt_UMLWidget; } // Get the first item and its base type UMLWidget * pTemp = (UMLWidget *) selectedWidgets().first(); WidgetBase::WidgetType tmpType = pTemp->baseType(); // Check all selected items, if they have the same BaseType foreach(pTemp, selectedWidgets()) { if (pTemp->baseType() != tmpType) { return WidgetBase::wt_UMLWidget; } } return tmpType; } /** * Asks for confirmation and clears everything on the diagram. * Called from menus. */ void UMLScene::clearDiagram() { if (Dialog_Utils::askDeleteDiagram()) { removeAllWidgets(); } } /** * Apply an automatic layout. */ void UMLScene::applyLayout(const QString &variant) { DEBUG(DBG_SRC) << "layout = " << variant; LayoutGenerator r; r.generate(this, variant); r.apply(this); UMLApp::app()->slotZoomFit(); } /** * Changes snap to grid boolean. * Called from menus. */ void UMLScene::toggleSnapToGrid() { setSnapToGrid(!snapToGrid()); } /** * Changes snap to grid for component size boolean. * Called from menus. */ void UMLScene::toggleSnapComponentSizeToGrid() { setSnapComponentSizeToGrid(!snapComponentSizeToGrid()); } /** * Changes show grid boolean. * Called from menus. */ void UMLScene::toggleShowGrid() { setSnapGridVisible(!isSnapGridVisible()); } /** * Return whether to use snap to grid. */ bool UMLScene::snapToGrid() const { return m_bUseSnapToGrid; } /** * Sets whether to snap to grid. */ void UMLScene::setSnapToGrid(bool bSnap) { m_bUseSnapToGrid = bSnap; emit sigSnapToGridToggled(snapToGrid()); } /** * Return whether to use snap to grid for component size. */ bool UMLScene::snapComponentSizeToGrid() const { return m_bUseSnapComponentSizeToGrid; } /** * Sets whether to snap to grid for component size. */ void UMLScene::setSnapComponentSizeToGrid(bool bSnap) { m_bUseSnapComponentSizeToGrid = bSnap; updateComponentSizes(); emit sigSnapComponentSizeToGridToggled(snapComponentSizeToGrid()); } /** * Returns the x grid size. */ int UMLScene::snapX() const { return m_layoutGrid->gridSpacingX(); } /** * Returns the y grid size. */ int UMLScene::snapY() const { return m_layoutGrid->gridSpacingY(); } /** * Sets the grid size in x and y. */ void UMLScene::setSnapSpacing(int x, int y) { m_layoutGrid->setGridSpacing(x, y); } /** * Returns the input coordinate with possible grid-snap applied. */ qreal UMLScene::snappedX(qreal _x) { if (snapToGrid()) { int x = (int)_x; int gridX = snapX(); int modX = x % gridX; x -= modX; if (modX >= gridX / 2) x += gridX; return x; } else return _x; } /** * Returns the input coordinate with possible grid-snap applied. */ qreal UMLScene::snappedY(qreal _y) { if (snapToGrid()) { int y = (int)_y; int gridY = snapY(); int modY = y % gridY; y -= modY; if (modY >= gridY / 2) y += gridY; return y; } else return _y; } /** * Returns whether to show snap grid or not. */ bool UMLScene::isSnapGridVisible() const { return m_layoutGrid->isVisible(); } /** * Sets whether to show snap grid. */ void UMLScene::setSnapGridVisible(bool bShow) { m_layoutGrid->setVisible(bShow); emit sigShowGridToggled(bShow); } /** * Returns whether to show documentation indicator. */ bool UMLScene::isShowDocumentationIndicator() const { return m_showDocumentationIndicator; } /** * sets whether to show documentation indicator. */ void UMLScene::setShowDocumentationIndicator(bool bShow) { m_showDocumentationIndicator = bShow; } /** * Returns whether to show operation signatures. */ bool UMLScene::showOpSig() const { return m_Options.classState.showOpSig; } /** * Sets whether to show operation signatures. */ void UMLScene::setShowOpSig(bool bShowOpSig) { m_Options.classState.showOpSig = bShowOpSig; } /** * Changes the zoom to the currently set level (now loaded from file) * Called from UMLApp::slotUpdateViews() */ void UMLScene::fileLoaded() { m_view->setZoom(m_view->zoom()); resizeSceneToItems(); } /** * Sets the size of the scene to just fit on all the items */ void UMLScene::resizeSceneToItems() { // let QGraphicsScene handle scene size by itself setSceneRect(QRectF()); } /** * Updates the size of all components in this view. */ void UMLScene::updateComponentSizes() { // update sizes of all components foreach(UMLWidget *obj, widgetList()) { uIgnoreZeroPointer(obj); obj->updateGeometry(); } } /** * Force the widget font metrics to be updated next time * the widgets are drawn. * This is necessary because the widget size might depend on the * font metrics and the font metrics might change for different * QPainter, i.e. font metrics for Display font and Printer font are * usually different. * Call this when you change the QPainter. */ void UMLScene::forceUpdateWidgetFontMetrics(QPainter * painter) { foreach(UMLWidget *obj, widgetList()) { uIgnoreZeroPointer(obj); obj->forceUpdateFontMetrics(painter); } } /** * Overrides standard method from QGraphicsScene drawing the background. */ void UMLScene::drawBackground(QPainter *painter, const QRectF &rect) { QGraphicsScene::drawBackground(painter, rect); m_layoutGrid->paint(painter, rect); } /** * Creates the "diagram" tag and fills it with the contents of the diagram. */ void UMLScene::saveToXMI1(QDomDocument & qDoc, QDomElement & qElement) { resizeSceneToItems(); QDomElement viewElement = qDoc.createElement(QLatin1String("diagram")); viewElement.setAttribute(QLatin1String("xmi.id"), Uml::ID::toString(m_nID)); viewElement.setAttribute(QLatin1String("name"), name()); viewElement.setAttribute(QLatin1String("type"), m_Type); viewElement.setAttribute(QLatin1String("documentation"), m_Documentation); //option state m_Options.saveToXMI1(viewElement); //misc viewElement.setAttribute(QLatin1String("localid"), Uml::ID::toString(m_nLocalID)); viewElement.setAttribute(QLatin1String("showgrid"), m_layoutGrid->isVisible()); viewElement.setAttribute(QLatin1String("snapgrid"), m_bUseSnapToGrid); viewElement.setAttribute(QLatin1String("snapcsgrid"), m_bUseSnapComponentSizeToGrid); viewElement.setAttribute(QLatin1String("snapx"), m_layoutGrid->gridSpacingX()); viewElement.setAttribute(QLatin1String("snapy"), m_layoutGrid->gridSpacingY()); // FIXME: move to UMLView viewElement.setAttribute(QLatin1String("zoom"), activeView()->zoom()); viewElement.setAttribute(QLatin1String("canvasheight"), QString::number(height())); viewElement.setAttribute(QLatin1String("canvaswidth"), QString::number(width())); viewElement.setAttribute(QLatin1String("isopen"), isOpen()); if (type() == Uml::DiagramType::Sequence || type() == Uml::DiagramType::Collaboration) viewElement.setAttribute(QLatin1String("autoincrementsequence"), autoIncrementSequence()); //now save all the widgets QDomElement widgetElement = qDoc.createElement(QLatin1String("widgets")); foreach(UMLWidget *widget, widgetList()) { uIgnoreZeroPointer(widget); // do not save floating text widgets having a parent widget; they are saved as part of the parent if (widget->isTextWidget() && widget->parentItem()) continue; // Having an exception is bad I know, but gotta work with // system we are given. // We DON'T want to record any text widgets which are belonging // to associations as they are recorded later in the "associations" // section when each owning association is dumped. -b.t. if ((!widget->isTextWidget() && !widget->isFloatingDashLineWidget()) || (widget->asFloatingTextWidget() && widget->asFloatingTextWidget()->link() == 0)) widget->saveToXMI1(qDoc, widgetElement); } viewElement.appendChild(widgetElement); //now save the message widgets QDomElement messageElement = qDoc.createElement(QLatin1String("messages")); foreach(UMLWidget* widget, messageList()) { widget->saveToXMI1(qDoc, messageElement); } viewElement.appendChild(messageElement); //now save the associations QDomElement assocElement = qDoc.createElement(QLatin1String("associations")); if (associationList().count()) { // We guard against (associationList().count() == 0) because // this code could be reached as follows: // ^ UMLScene::saveToXMI1() // ^ UMLDoc::saveToXMI1() // ^ UMLDoc::addToUndoStack() // ^ UMLDoc::setModified() // ^ UMLDoc::createDiagram() // ^ UMLDoc::newDocument() // ^ UMLApp::newDocument() // ^ main() // AssociationWidget * assoc = 0; foreach(assoc, associationList()) { assoc->saveToXMI1(qDoc, assocElement); } } viewElement.appendChild(assocElement); qElement.appendChild(viewElement); } /** * Loads the "diagram" tag. */ bool UMLScene::loadFromXMI1(QDomElement & qElement) { QString id = qElement.attribute(QLatin1String("xmi.id"), QLatin1String("-1")); m_nID = Uml::ID::fromString(id); if (m_nID == Uml::ID::None) return false; setName(qElement.attribute(QLatin1String("name"))); QString type = qElement.attribute(QLatin1String("type"), QLatin1String("0")); m_Documentation = qElement.attribute(QLatin1String("documentation")); QString localid = qElement.attribute(QLatin1String("localid"), QLatin1String("0")); // option state m_Options.loadFromXMI1(qElement); setBackgroundBrush(m_Options.uiState.backgroundColor); setGridDotColor(m_Options.uiState.gridDotColor); //misc QString showgrid = qElement.attribute(QLatin1String("showgrid"), QLatin1String("0")); m_layoutGrid->setVisible((bool)showgrid.toInt()); QString snapgrid = qElement.attribute(QLatin1String("snapgrid"), QLatin1String("0")); m_bUseSnapToGrid = (bool)snapgrid.toInt(); QString snapcsgrid = qElement.attribute(QLatin1String("snapcsgrid"), QLatin1String("0")); m_bUseSnapComponentSizeToGrid = (bool)snapcsgrid.toInt(); QString snapx = qElement.attribute(QLatin1String("snapx"), QLatin1String("10")); QString snapy = qElement.attribute(QLatin1String("snapy"), QLatin1String("10")); m_layoutGrid->setGridSpacing(snapx.toInt(), snapy.toInt()); QString zoom = qElement.attribute(QLatin1String("zoom"), QLatin1String("100")); activeView()->setZoom(zoom.toInt()); resizeSceneToItems(); QString isOpen = qElement.attribute(QLatin1String("isopen"), QLatin1String("1")); m_isOpen = (bool)isOpen.toInt(); int nType = type.toInt(); if (nType == -1 || nType >= 400) { // Pre 1.5.5 numeric values // Values of "type" were changed in 1.5.5 to merge with Settings::Diagram switch (nType) { case 400: m_Type = Uml::DiagramType::UseCase; break; case 401: m_Type = Uml::DiagramType::Collaboration; break; case 402: m_Type = Uml::DiagramType::Class; break; case 403: m_Type = Uml::DiagramType::Sequence; break; case 404: m_Type = Uml::DiagramType::State; break; case 405: m_Type = Uml::DiagramType::Activity; break; case 406: m_Type = Uml::DiagramType::Component; break; case 407: m_Type = Uml::DiagramType::Deployment; break; case 408: m_Type = Uml::DiagramType::EntityRelationship; break; case 409: m_Type = Uml::DiagramType::Object; break; default: m_Type = Uml::DiagramType::Undefined; break; } } else { m_Type = Uml::DiagramType::fromInt(nType); } m_nLocalID = Uml::ID::fromString(localid); if (m_Type == Uml::DiagramType::Sequence || m_Type == Uml::DiagramType::Collaboration) { QString autoIncrementSequence = qElement.attribute(QLatin1String("autoincrementsequence"), QLatin1String("0")); m_autoIncrementSequence = (bool)autoIncrementSequence.toInt(); } QDomNode node = qElement.firstChild(); bool widgetsLoaded = false, messagesLoaded = false, associationsLoaded = false; while (!node.isNull()) { QDomElement element = node.toElement(); if (!element.isNull()) { if (element.tagName() == QLatin1String("widgets")) widgetsLoaded = loadWidgetsFromXMI(element); else if (element.tagName() == QLatin1String("messages")) messagesLoaded = loadMessagesFromXMI(element); else if (element.tagName() == QLatin1String("associations")) associationsLoaded = loadAssociationsFromXMI(element); } node = node.nextSibling(); } if (!widgetsLoaded) { uWarning() << "failed UMLScene load on widgets"; return false; } if (!messagesLoaded) { uWarning() << "failed UMLScene load on messages"; return false; } if (!associationsLoaded) { uWarning() << "failed UMLScene load on associations"; return false; } if (this->type() == Uml::DiagramType::Component) { m_d->addMissingPorts(); m_d->fixPortPositions(); } m_d->removeDuplicatedFloatingTextInstances(); return true; } bool UMLScene::loadWidgetsFromXMI(QDomElement & qElement) { UMLWidget* widget = 0; QDomNode node = qElement.firstChild(); QDomElement widgetElement = node.toElement(); while (!widgetElement.isNull()) { widget = loadWidgetFromXMI(widgetElement); if (widget) { addWidgetCmd(widget); widget->clipSize(); // In the interest of best-effort loading, in case of a // (widget == 0) we still go on. // The individual widget's loadFromXMI1 method should // already have generated an error message to tell the // user that something went wrong. } node = widgetElement.nextSibling(); widgetElement = node.toElement(); } return true; } /** * Loads a "widget" element from XMI, used by loadFromXMI1() and the clipboard. */ UMLWidget* UMLScene::loadWidgetFromXMI(QDomElement& widgetElement) { if (!m_doc) { uWarning() << "m_doc is NULL"; return 0L; } QString tag = widgetElement.tagName(); QString idstr = widgetElement.attribute(QLatin1String("xmi.id"), QLatin1String("-1")); UMLWidget* widget = Widget_Factory::makeWidgetFromXMI(tag, idstr, this); if (widget == 0) return 0; if (!widget->loadFromXMI1(widgetElement)) { widget->cleanup(); delete widget; return 0; } return widget; } bool UMLScene::loadMessagesFromXMI(QDomElement & qElement) { MessageWidget * message = 0; QDomNode node = qElement.firstChild(); QDomElement messageElement = node.toElement(); while (!messageElement.isNull()) { QString tag = messageElement.tagName(); DEBUG(DBG_SRC) << "tag = " << tag; if (tag == QLatin1String("messagewidget") || tag == QLatin1String("UML:MessageWidget")) { // for bkwd compatibility message = new MessageWidget(this, SequenceMessage::Asynchronous, Uml::ID::Reserved); if (!message->loadFromXMI1(messageElement)) { delete message; return false; } addWidgetCmd(message); FloatingTextWidget *ft = message->floatingTextWidget(); if (!ft && message->sequenceMessageType() != SequenceMessage::Creation) DEBUG(DBG_SRC) << "floating text is NULL for message " << Uml::ID::toString(message->id()); } node = messageElement.nextSibling(); messageElement = node.toElement(); } return true; } bool UMLScene::loadAssociationsFromXMI(QDomElement & qElement) { QDomNode node = qElement.firstChild(); QDomElement assocElement = node.toElement(); int countr = 0; while (!assocElement.isNull()) { QString tag = assocElement.tagName(); if (tag == QLatin1String("assocwidget") || tag == QLatin1String("UML:AssocWidget")) { // for bkwd compatibility countr++; AssociationWidget *assoc = AssociationWidget::create(this); if (!assoc->loadFromXMI1(assocElement)) { uError() << "could not loadFromXMI1 association widget:" << assoc << ", bad XMI file? Deleting from UMLScene."; delete assoc; /* return false; Returning false here is a little harsh when the rest of the diagram might load okay. */ } else { assoc->clipSize(); if (!addAssociation(assoc, false)) { uError() << "Could not addAssociation(" << assoc << ") to UMLScene, deleting."; delete assoc; //return false; // soften error.. may not be that bad } } } node = assocElement.nextSibling(); assocElement = node.toElement(); } return true; } /** * Add an object to the application, and update the view. */ void UMLScene::addObject(UMLObject *object) { m_bCreateObject = true; if (m_doc->addUMLObject(object)) m_doc->signalUMLObjectCreated(object); // m_bCreateObject is reset by slotObjectCreated() else m_bCreateObject = false; } bool UMLScene::loadUisDiagramPresentation(QDomElement & qElement) { for (QDomNode node = qElement.firstChild(); !node.isNull(); node = node.nextSibling()) { QDomElement elem = node.toElement(); QString tag = elem.tagName(); if (! UMLDoc::tagEq(tag, QLatin1String("Presentation"))) { uError() << "ignoring unknown UisDiagramPresentation tag " << tag; continue; } QDomNode n = elem.firstChild(); QDomElement e = n.toElement(); QString idStr; int x = 0, y = 0, w = 0, h = 0; while (!e.isNull()) { tag = e.tagName(); DEBUG(DBG_SRC) << "Presentation: tag = " << tag; if (UMLDoc::tagEq(tag, QLatin1String("Presentation.geometry"))) { QDomNode gnode = e.firstChild(); QDomElement gelem = gnode.toElement(); QString csv = gelem.text(); QStringList dim = csv.split(QLatin1Char(',')); x = dim[0].toInt(); y = dim[1].toInt(); w = dim[2].toInt(); h = dim[3].toInt(); } else if (UMLDoc::tagEq(tag, QLatin1String("Presentation.style"))) { // TBD } else if (UMLDoc::tagEq(tag, QLatin1String("Presentation.model"))) { QDomNode mnode = e.firstChild(); QDomElement melem = mnode.toElement(); idStr = melem.attribute(QLatin1String("xmi.idref")); } else { DEBUG(DBG_SRC) << "ignoring tag " << tag; } n = n.nextSibling(); e = n.toElement(); } Uml::ID::Type id = Uml::ID::fromString(idStr); UMLObject *o = m_doc->findObjectById(id); if (o == 0) { uError() << "Cannot find object for id " << idStr; } else { UMLObject::ObjectType ot = o->baseType(); DEBUG(DBG_SRC) << "Create widget for model object of type " << UMLObject::toString(ot); UMLWidget *widget = 0; switch (ot) { case UMLObject::ot_Class: widget = new ClassifierWidget(this, o->asUMLClassifier()); break; case UMLObject::ot_Association: { UMLAssociation *umla = o->asUMLAssociation(); Uml::AssociationType::Enum at = umla->getAssocType(); UMLObject* objA = umla->getObject(Uml::RoleType::A); UMLObject* objB = umla->getObject(Uml::RoleType::B); if (objA == 0 || objB == 0) { uError() << "intern err 1"; return false; } UMLWidget *wA = findWidget(objA->id()); UMLWidget *wB = findWidget(objB->id()); if (wA != 0 && wB != 0) { AssociationWidget *aw = AssociationWidget::create(this, wA, at, wB, umla); aw->syncToModel(); addWidgetCmd(aw); } else { uError() << "cannot create assocwidget from (" ; //<< wA << ", " << wB << ")"; } break; } case UMLObject::ot_Role: { //UMLRole *robj = o->asUMLRole(); //UMLAssociation *umla = robj->getParentAssociation(); // @todo properly display role names. // For now, in order to get the role names displayed // simply delete the participating diagram objects // and drag them from the list view to the diagram. break; } default: uError() << "Cannot create widget of type " << ot; } if (widget) { DEBUG(DBG_SRC) << "Widget: x=" << x << ", y=" << y << ", w=" << w << ", h=" << h; widget->setX(x); widget->setY(y); widget->setSize(w, h); addWidgetCmd(widget); } } } return true; } /** * Loads the "UISDiagram" tag of Unisys.IntegratePlus.2 generated files. */ bool UMLScene::loadUISDiagram(QDomElement & qElement) { QString idStr = qElement.attribute(QLatin1String("xmi.id")); if (idStr.isEmpty()) return false; m_nID = Uml::ID::fromString(idStr); UMLListViewItem *ulvi = 0; for (QDomNode node = qElement.firstChild(); !node.isNull(); node = node.nextSibling()) { if (node.isComment()) continue; QDomElement elem = node.toElement(); QString tag = elem.tagName(); if (tag == QLatin1String("uisDiagramName")) { setName(elem.text()); if (ulvi) ulvi->setText(name()); } else if (tag == QLatin1String("uisDiagramStyle")) { QString diagramStyle = elem.text(); if (diagramStyle != QLatin1String("ClassDiagram")) { uError() << "diagram style " << diagramStyle << " is not yet implemented"; continue; } m_doc->setMainViewID(m_nID); m_Type = Uml::DiagramType::Class; UMLListView *lv = UMLApp::app()->listView(); ulvi = new UMLListViewItem(lv->theLogicalView(), name(), UMLListViewItem::lvt_Class_Diagram, m_nID); } else if (tag == QLatin1String("uisDiagramPresentation")) { loadUisDiagramPresentation(elem); } else if (tag != QLatin1String("uisToolName")) { DEBUG(DBG_SRC) << "ignoring tag " << tag; } } return true; } /** * Left Alignment */ void UMLScene::alignLeft() { UMLWidgetList widgetList = selectedWidgetsExt(); if (widgetList.isEmpty()) return; qreal smallestX = WidgetList_Utils::getSmallestX(widgetList); foreach(UMLWidget *widget, widgetList) { widget->setX(smallestX); widget->adjustAssocs(widget->x(), widget->y()); } //TODO: Push stored cmds to stack. } /** * Right Alignment */ void UMLScene::alignRight() { UMLWidgetList widgetList = selectedWidgetsExt(); if (widgetList.isEmpty()) return; qreal biggestX = WidgetList_Utils::getBiggestX(widgetList); foreach(UMLWidget *widget, widgetList) { widget->setX(biggestX - widget->width()); widget->adjustAssocs(widget->x(), widget->y()); } //TODO: Push stored cmds to stack. } /** * Top Alignment */ void UMLScene::alignTop() { UMLWidgetList widgetList = selectedWidgetsExt(); if (widgetList.isEmpty()) return; qreal smallestY = WidgetList_Utils::getSmallestY(widgetList); foreach(UMLWidget *widget, widgetList) { widget->setY(smallestY); widget->adjustAssocs(widget->x(), widget->y()); } //TODO: Push stored cmds to stack. } /** * Bottom Alignment */ void UMLScene::alignBottom() { UMLWidgetList widgetList = selectedWidgetsExt(); if (widgetList.isEmpty()) return; qreal biggestY = WidgetList_Utils::getBiggestY(widgetList); foreach(UMLWidget *widget, widgetList) { widget->setY(biggestY - widget->height()); widget->adjustAssocs(widget->x(), widget->y()); } //TODO: Push stored cmds to stack. } /** * Vertical Middle Alignment */ void UMLScene::alignVerticalMiddle() { UMLWidgetList widgetList = selectedWidgetsExt(); if (widgetList.isEmpty()) return; qreal smallestY = WidgetList_Utils::getSmallestY(widgetList); qreal biggestY = WidgetList_Utils::getBiggestY(widgetList); qreal middle = int((biggestY - smallestY) / 2) + smallestY; foreach(UMLWidget *widget, widgetList) { widget->setY(middle - widget->height() / 2); widget->adjustAssocs(widget->x(), widget->y()); } AssociationWidgetList assocList = selectedAssocs(); if (!assocList.isEmpty()) { foreach (AssociationWidget *widget, assocList) { widget->setYEntireAssoc(middle); } } //TODO: Push stored cmds to stack. } /** * Horizontal Middle Alignment */ void UMLScene::alignHorizontalMiddle() { UMLWidgetList widgetList = selectedWidgetsExt(); if (widgetList.isEmpty()) return; qreal smallestX = WidgetList_Utils::getSmallestX(widgetList); qreal biggestX = WidgetList_Utils::getBiggestX(widgetList); qreal middle = int((biggestX - smallestX) / 2) + smallestX; foreach(UMLWidget *widget, widgetList) { widget->setX(middle - widget->width() / 2); widget->adjustAssocs(widget->x(), widget->y()); } AssociationWidgetList assocList = selectedAssocs(); if (!assocList.isEmpty()) { foreach (AssociationWidget *widget, assocList) { widget->setXEntireAssoc(middle); } } //TODO: Push stored cmds to stack. } /** * Vertical Distribute Alignment */ void UMLScene::alignVerticalDistribute() { UMLWidgetList widgetList = selectedWidgetsExt(); if (widgetList.isEmpty()) return; qreal smallestY = WidgetList_Utils::getSmallestY(widgetList); qreal biggestY = WidgetList_Utils::getBiggestY(widgetList); qreal heightsSum = WidgetList_Utils::getHeightsSum(widgetList); qreal distance = int(((biggestY - smallestY) - heightsSum) / (widgetList.count() - 1.0) + 0.5); qSort(widgetList.begin(), widgetList.end(), Widget_Utils::hasSmallerY); int i = 1; UMLWidget* widgetPrev = 0; foreach(UMLWidget *widget, widgetList) { if (i == 1) { widgetPrev = widget; } else { widget->setY(widgetPrev->y() + widgetPrev->height() + distance); widget->adjustAssocs(widget->x(), widget->y()); widgetPrev = widget; } i++; } //TODO: Push stored cmds to stack. } /** * Horizontal Distribute Alignment */ void UMLScene::alignHorizontalDistribute() { UMLWidgetList widgetList = selectedWidgetsExt(); if (widgetList.isEmpty()) return; qreal smallestX = WidgetList_Utils::getSmallestX(widgetList); qreal biggestX = WidgetList_Utils::getBiggestX(widgetList); qreal widthsSum = WidgetList_Utils::getWidthsSum(widgetList); qreal distance = int(((biggestX - smallestX) - widthsSum) / (widgetList.count() - 1.0) + 0.5); qSort(widgetList.begin(), widgetList.end(), Widget_Utils::hasSmallerX); int i = 1; UMLWidget* widgetPrev = 0; foreach(UMLWidget *widget, widgetList) { if (i == 1) { widgetPrev = widget; } else { widget->setX(widgetPrev->x() + widgetPrev->width() + distance); widget->adjustAssocs(widget->x(), widget->y()); widgetPrev = widget; } i++; } //TODO: Push stored cmds to stack. } /** * Overloading operator for debugging output. */ QDebug operator<<(QDebug dbg, UMLScene *item) { dbg.nospace() << "UMLScene: " << item->name() << " / type=" << DiagramType::toString(item->type()) << " / id=" << Uml::ID::toString(item->ID()) << " / isOpen=" << item->isOpen(); return dbg.space(); } diff --git a/umbrello/umlwidgets/interfacewidget.cpp b/umbrello/umlwidgets/interfacewidget.cpp new file mode 100644 index 000000000..b2656af28 --- /dev/null +++ b/umbrello/umlwidgets/interfacewidget.cpp @@ -0,0 +1,23 @@ +/*************************************************************************** + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * copyright (C) 2019 * + * Umbrello UML Modeller Authors * + ***************************************************************************/ + +#include "interfacewidget.h" + +InterfaceWidget::InterfaceWidget(UMLScene *scene, UMLClassifier *c) + : ClassifierWidget(scene, c) +{ + +} + +InterfaceWidget::InterfaceWidget(UMLScene *scene, UMLPackage *p) + : ClassifierWidget(scene, p) +{ + +} diff --git a/umbrello/umlwidgets/interfacewidget.h b/umbrello/umlwidgets/interfacewidget.h new file mode 100644 index 000000000..1466e4918 --- /dev/null +++ b/umbrello/umlwidgets/interfacewidget.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * copyright (C) 2019 * + * Umbrello UML Modeller Authors * + ***************************************************************************/ + +#ifndef INTERFACEWIDGET_H +#define INTERFACEWIDGET_H + +#include "classifierwidget.h" + +/** + * Provides an interface widget + * + * The implementation is currently in @ref ClassifierWidget + * and should be moved to this class for easier implementation + * + * @author Ralf Habacker + */ +class InterfaceWidget : public ClassifierWidget +{ +public: + InterfaceWidget(UMLScene * scene, UMLClassifier * c); + InterfaceWidget(UMLScene * scene, UMLPackage * p); +}; + +#endif // INTERFACEWIDGET_H diff --git a/umbrello/umlwidgets/widget_factory.cpp b/umbrello/umlwidgets/widget_factory.cpp index 7f43a8b41..f1c8f7038 100644 --- a/umbrello/umlwidgets/widget_factory.cpp +++ b/umbrello/umlwidgets/widget_factory.cpp @@ -1,310 +1,311 @@ /*************************************************************************** * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * copyright (C) 2006-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "widget_factory.h" // app includes #include "activitywidget.h" #include "actor.h" #include "actorwidget.h" #include "artifact.h" #include "artifactwidget.h" #include "associationwidget.h" #include "boxwidget.h" #include "category.h" #include "categorywidget.h" #include "classifier.h" #include "classifierwidget.h" #include "cmds.h" #include "combinedfragmentwidget.h" #include "component.h" #include "componentwidget.h" #include "datatypewidget.h" #include "debug_utils.h" #include "entity.h" #include "entitywidget.h" #include "enum.h" #include "enumwidget.h" #include "instance.h" #include "floatingdashlinewidget.h" #include "floatingtextwidget.h" #include "folder.h" #include "forkjoinwidget.h" +#include "interfacewidget.h" #include "messagewidget.h" #include "node.h" #include "nodewidget.h" #include "notewidget.h" #include "object_factory.h" #include "objectnodewidget.h" #include "objectwidget.h" #include "package.h" #include "packagewidget.h" #include "pinwidget.h" #include "port.h" #include "portwidget.h" #include "preconditionwidget.h" #include "regionwidget.h" #include "signalwidget.h" #include "statewidget.h" #include "uml.h" #include "umldoc.h" #include "umlscene.h" #include "umlview.h" #include "usecase.h" #include "usecasewidget.h" namespace Widget_Factory { /** * Create a UMLWidget in the given view and representing the given document object. */ UMLWidget *createWidget(UMLScene *scene, UMLObject *o) { QPointF pos = scene->pos(); int y = pos.y(); Uml::DiagramType::Enum diagramType = scene->type(); UMLObject::ObjectType type = o->baseType(); UMLWidget *newWidget = 0; switch (type) { case UMLObject::ot_Actor: if (diagramType == Uml::DiagramType::Sequence) { ObjectWidget *ow = new ObjectWidget(scene, o); ow->setDrawAsActor(true); y = ow->topMargin(); newWidget = ow; } else newWidget = new ActorWidget(scene, o->asUMLActor()); break; case UMLObject::ot_UseCase: newWidget = new UseCaseWidget(scene, o->asUMLUseCase()); break; case UMLObject::ot_Folder: newWidget = new PackageWidget(scene, o->asUMLPackage()); break; case UMLObject::ot_Package: newWidget = new ClassifierWidget(scene, o->asUMLPackage()); break; case UMLObject::ot_Component: newWidget = new ComponentWidget(scene, o->asUMLComponent()); if (diagramType == Uml::DiagramType::Deployment) { newWidget->setIsInstance(true); } break; case UMLObject::ot_Port: { newWidget = new PortWidget(scene, o->asUMLPort()); } break; case UMLObject::ot_Node: newWidget = new NodeWidget(scene, o->asUMLNode()); break; case UMLObject::ot_Artifact: newWidget = new ArtifactWidget(scene, o->asUMLArtifact()); break; case UMLObject::ot_Datatype: newWidget = new DatatypeWidget(scene, o->asUMLClassifier()); break; case UMLObject::ot_Enum: newWidget = new EnumWidget(scene, o->asUMLEnum()); break; case UMLObject::ot_Entity: newWidget = new EntityWidget(scene, o->asUMLEntity()); break; case UMLObject::ot_Interface: if (diagramType == Uml::DiagramType::Sequence || diagramType == Uml::DiagramType::Collaboration) { ObjectWidget *ow = new ObjectWidget(scene, o); if (diagramType == Uml::DiagramType::Sequence) { y = ow->topMargin(); } newWidget = ow; } else { UMLClassifier *c = o->asUMLClassifier(); - ClassifierWidget* interfaceWidget = new ClassifierWidget(scene, c); + InterfaceWidget* interfaceWidget = new InterfaceWidget(scene, c); if (diagramType == Uml::DiagramType::Component || diagramType == Uml::DiagramType::Deployment) { interfaceWidget->setDrawAsCircle(true); } newWidget = interfaceWidget; } break; case UMLObject::ot_Class: if (diagramType == Uml::DiagramType::Object) break; //see if we really want an object widget or class widget if (diagramType == Uml::DiagramType::Class || diagramType == Uml::DiagramType::Component) { UMLClassifier *c = o->asUMLClassifier(); ClassifierWidget *cw = new ClassifierWidget(scene, c); if (diagramType == Uml::DiagramType::Component) cw->setDrawAsCircle(true); newWidget = cw; } else { ObjectWidget *ow = new ObjectWidget(scene, o); if (diagramType == Uml::DiagramType::Sequence) { y = ow->topMargin(); } newWidget = ow; } break; case UMLObject::ot_Instance: newWidget = new ClassifierWidget(scene, o->asUMLInstance()); break; case UMLObject::ot_Category: newWidget = new CategoryWidget(scene, o->asUMLCategory()); break; default: uWarning() << "trying to create an invalid widget (" << UMLObject::toString(type) << ")"; } if (newWidget) { uDebug() << "Widget_Factory::createWidget(" << newWidget->baseType() << ")"; if (newWidget->baseType() != WidgetBase::wt_Pin && newWidget->baseType() != WidgetBase::wt_Port) { newWidget->setX(pos.x()); newWidget->setY(y); } } return newWidget; } bool validateObjType(UMLObject::ObjectType expected, UMLObject* &o, Uml::ID::Type id) { if (o == 0) { uDebug() << "Widget_Factory::validateObjType: creating new object of type " << expected; QString artificialName = QLatin1String("LOST_") + Uml::ID::toString(id); o = Object_Factory::createUMLObject(expected, artificialName, 0, false); if (o == 0) return false; o->setID(id); UMLPackage *parentPkg = o->umlPackage(); parentPkg->addObject(o); return true; } UMLObject::ObjectType actual = o->baseType(); if (actual == expected) return true; uError() << "validateObjType(" << o->name() << "): expected type " << UMLObject::toString(expected) << ", actual type " << UMLObject::toString(actual); return false; } /** * Create a UMLWidget according to the given XMI tag. */ UMLWidget* makeWidgetFromXMI(const QString& tag, const QString& idStr, UMLScene *scene) { UMLWidget *widget = 0; // Loading of widgets which do NOT represent any UMLObject, // just graphic stuff with no real model information //FIXME while boxes and texts are just diagram objects, activities and // states should be UMLObjects if (tag == QLatin1String("statewidget") || tag == QLatin1String("UML:StateWidget")) { widget = new StateWidget(scene, StateWidget::Normal, Uml::ID::Reserved); } else if (tag == QLatin1String("notewidget") || tag == QLatin1String("UML:NoteWidget")) { widget = new NoteWidget(scene, NoteWidget::Normal, Uml::ID::Reserved); } else if (tag == QLatin1String("boxwidget")) { widget = new BoxWidget(scene, Uml::ID::Reserved); } else if (tag == QLatin1String("floatingtext") || tag == QLatin1String("UML:FloatingTextWidget")) { widget = new FloatingTextWidget(scene, Uml::TextRole::Floating, QString(), Uml::ID::Reserved); } else if (tag == QLatin1String("activitywidget") || tag == QLatin1String("UML:ActivityWidget")) { widget = new ActivityWidget(scene, ActivityWidget::Initial, Uml::ID::Reserved); } else if (tag == QLatin1String("messagewidget")) { widget = new MessageWidget(scene, Uml::SequenceMessage::Asynchronous, Uml::ID::Reserved); } else if (tag == QLatin1String("forkjoin")) { widget = new ForkJoinWidget(scene, Qt::Vertical, Uml::ID::Reserved); } else if (tag == QLatin1String("preconditionwidget")) { widget = new PreconditionWidget(scene, 0, Uml::ID::Reserved); } else if (tag == QLatin1String("combinedFragmentwidget")) { widget = new CombinedFragmentWidget(scene, CombinedFragmentWidget::Ref, Uml::ID::Reserved); } else if (tag == QLatin1String("signalwidget")) { widget = new SignalWidget(scene, SignalWidget::Send, Uml::ID::Reserved); } else if (tag == QLatin1String("floatingdashlinewidget")) { widget = new FloatingDashLineWidget(scene, Uml::ID::Reserved); } else if (tag == QLatin1String("objectnodewidget")) { widget = new ObjectNodeWidget(scene, ObjectNodeWidget::Normal, Uml::ID::Reserved); } else if (tag == QLatin1String("regionwidget")) { widget = new RegionWidget(scene, Uml::ID::Reserved); } else if (tag == QLatin1String("pinwidget")) { widget = new PinWidget(scene, 0, Uml::ID::Reserved); } else { // Loading of widgets which represent an UMLObject // Find the UMLObject and create the Widget to represent it Uml::ID::Type id = Uml::ID::fromString(idStr); UMLDoc *umldoc = UMLApp::app()->document(); UMLObject *o = umldoc->findObjectById(id); if (o == 0) { uDebug() << "makeWidgetFromXMI: cannot find object with id " << Uml::ID::toString(id); } if (tag == QLatin1String("actorwidget") || tag == QLatin1String("UML:ActorWidget")) { if (validateObjType(UMLObject::ot_Actor, o, id)) widget = new ActorWidget(scene, o->asUMLActor()); } else if (tag == QLatin1String("usecasewidget") || tag == QLatin1String("UML:UseCaseWidget")) { if (validateObjType(UMLObject::ot_UseCase, o, id)) widget = new UseCaseWidget(scene, o->asUMLUseCase()); } else if (tag == QLatin1String("classwidget") || tag == QLatin1String("UML:ClassWidget") || tag == QLatin1String("UML:ConceptWidget")) { if (validateObjType(UMLObject::ot_Class, o, id) || validateObjType(UMLObject::ot_Package, o, id)) widget = new ClassifierWidget(scene, o->asUMLClassifier()); } else if (tag == QLatin1String("packagewidget")) { if (validateObjType(UMLObject::ot_Package, o, id)) widget = new ClassifierWidget(scene, o->asUMLPackage()); } else if (tag == QLatin1String("componentwidget")) { if (validateObjType(UMLObject::ot_Component, o, id)) widget = new ComponentWidget(scene, o->asUMLComponent()); } else if (tag == QLatin1String("portwidget")) { if (validateObjType(UMLObject::ot_Port, o, id)) widget = new PortWidget(scene, o->asUMLPort()); } else if (tag == QLatin1String("nodewidget")) { if (validateObjType(UMLObject::ot_Node, o, id)) widget = new NodeWidget(scene, o->asUMLNode()); } else if (tag == QLatin1String("artifactwidget")) { if (validateObjType(UMLObject::ot_Artifact, o, id)) widget = new ArtifactWidget(scene, o->asUMLArtifact()); } else if (tag == QLatin1String("interfacewidget")) { if (validateObjType(UMLObject::ot_Interface, o, id)) - widget = new ClassifierWidget(scene, o->asUMLClassifier()); + widget = new InterfaceWidget(scene, o->asUMLClassifier()); } else if (tag == QLatin1String("datatypewidget")) { if (validateObjType(UMLObject::ot_Datatype, o, id)) widget = new DatatypeWidget(scene, o->asUMLClassifier()); } else if (tag == QLatin1String("enumwidget")) { if (validateObjType(UMLObject::ot_Enum, o, id)) widget = new EnumWidget(scene, o->asUMLEnum()); } else if (tag == QLatin1String("entitywidget")) { if (validateObjType(UMLObject::ot_Entity, o, id)) widget = new EntityWidget(scene, o->asUMLEntity()); } else if (tag == QLatin1String("categorywidget")) { if (validateObjType(UMLObject::ot_Category, o, id)) widget = new CategoryWidget(scene, o->asUMLCategory()); } else if (tag == QLatin1String("objectwidget") || tag == QLatin1String("UML:ObjectWidget")) { widget = new ObjectWidget(scene, o); } else if(tag == QLatin1String("instancewidget") || tag == QLatin1String("UML:InstanceWidget")) { if (validateObjType(UMLObject::ot_Instance, o, id)) widget = new ClassifierWidget(scene, o->asUMLInstance()); } else { uWarning() << "Trying to create an unknown widget:" << tag; } } return widget; } } // end namespace Widget_Factory diff --git a/umbrello/umlwidgets/widgetbase.cpp b/umbrello/umlwidgets/widgetbase.cpp index 2046b42df..f3edab3b5 100644 --- a/umbrello/umlwidgets/widgetbase.cpp +++ b/umbrello/umlwidgets/widgetbase.cpp @@ -1,1348 +1,1348 @@ /*************************************************************************** * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * copyright (C) 2004-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ #include "widgetbase.h" #include "classifier.h" #include "debug_utils.h" #include "dialog_utils.h" #include "floatingtextwidget.h" #include "uml.h" #include "umldoc.h" #include "umllistview.h" #include "umlobject.h" #include "umlscene.h" #include "widgetbasepopupmenu.h" #if QT_VERSION < 0x050000 #include #include #endif #include #include #if QT_VERSION >= 0x050000 #include #include #endif #include /** * Creates a WidgetBase object. * * @param scene The view to be displayed on. * @param type The WidgetType to construct. This must be set to the appropriate * value by the constructors of inheriting classes. */ WidgetBase::WidgetBase(UMLScene *scene, WidgetType type) : QGraphicsObject(), m_baseType(type), m_scene(scene), m_umlObject(0), m_textColor(QColor("black")), m_fillColor(QColor("yellow")), m_brush(m_fillColor), m_lineWidth(0), // initialize with 0 to have valid start condition m_useFillColor(true), m_usesDiagramFillColor(true), m_usesDiagramLineColor(true), m_usesDiagramLineWidth(true), m_usesDiagramTextColor(true), m_usesDiagramUseFillColor(true), m_autoResize(true), m_changesShape(false) { Q_ASSERT(m_baseType > wt_Min && m_baseType < wt_Max); // Note: no virtual methods from derived classes available, // this operation need to be finished in derived class constructor. setLineColor(QColor("black")); setSelected(false); // TODO 310283 setFlags(ItemIsSelectable); //setFlags(ItemIsSelectable | ItemIsMovable |ItemSendsGeometryChanges); if (m_scene) { m_usesDiagramLineColor = true; m_usesDiagramLineWidth = true; m_usesDiagramTextColor = true; const Settings::OptionState& optionState = m_scene->optionState(); m_textColor = optionState.uiState.textColor; setLineColor(optionState.uiState.lineColor); setLineWidth(optionState.uiState.lineWidth); m_font = optionState.uiState.font; } else { uError() << "WidgetBase constructor: SERIOUS PROBLEM - m_scene is NULL"; } } /** * Destructor. */ WidgetBase::~WidgetBase() { } /** * Read property of m_baseType. */ WidgetBase::WidgetType WidgetBase::baseType() const { Q_ASSERT(m_baseType > wt_Min && m_baseType < wt_Max); return m_baseType; } /** * Set property m_baseType. Used for types changing their types during runtime. */ void WidgetBase::setBaseType(const WidgetType& baseType) { Q_ASSERT(baseType > wt_Min && baseType < wt_Max); m_baseType = baseType; } /** * @return The type used for rtti as string. */ QLatin1String WidgetBase::baseTypeStr() const { Q_ASSERT(m_baseType > wt_Min && m_baseType < wt_Max); return QLatin1String(ENUM_NAME(WidgetBase, WidgetType, m_baseType)); } /* * Sets the state of whether the widget is selected. * * @param select The state of whether the widget is selected. */ void WidgetBase::setSelected(bool select) { QGraphicsObject::setSelected(select); } /** * Deliver a pointer to the connected UMLView * (needed esp. by event handling of AssociationLine). */ UMLScene* WidgetBase::umlScene() const { return m_scene; } /** * This is shortcut method for UMLApp::app()->document(). * * @return Pointer to the UMLDoc object. */ UMLDoc* WidgetBase::umlDoc() const { return UMLApp::app()->document(); } /** * Returns the @ref UMLObject set to represent. * * @return the UMLObject to represent. */ UMLObject* WidgetBase::umlObject() const { return m_umlObject; } /** * Sets the @ref UMLObject to represent. * * @param obj The object to represent. */ void WidgetBase::setUMLObject(UMLObject *obj) { m_umlObject = obj; } /** * Write property of m_nId. */ void WidgetBase::setID(Uml::ID::Type id) { if (m_umlObject) { if (m_umlObject->id() != Uml::ID::None) uWarning() << "changing old UMLObject " << Uml::ID::toString(m_umlObject->id()) << " to " << Uml::ID::toString(id); m_umlObject->setID(id); } m_nId = id; } /** * Read property of m_nId. */ Uml::ID::Type WidgetBase::id() const { if (m_umlObject) return m_umlObject->id(); return m_nId; } /** * Used by some child classes to get documentation. * * @return The documentation from the UMLObject (if m_umlObject is set.) */ QString WidgetBase::documentation() const { if (m_umlObject) return m_umlObject->doc(); return m_Doc; } /** * Returns state of documentation for the widget. * * @return false if documentation is empty */ bool WidgetBase::hasDocumentation() { if (m_umlObject) return m_umlObject->hasDoc(); return !m_Doc.isEmpty(); } /** * Used by some child classes to set documentation. * * @param doc The documentation to be set in the UMLObject * (if m_umlObject is set.) */ void WidgetBase::setDocumentation(const QString& doc) { if (m_umlObject) m_umlObject->setDoc(doc); else m_Doc = doc; } /** * Gets the name from the corresponding UMLObject if this widget has an * underlying UMLObject; if it does not, then it returns the local * m_Text (notably the case for FloatingTextWidget.) * * @return the currently set name */ QString WidgetBase::name() const { if (m_umlObject) return m_umlObject->name(); return m_Text; } /** * Sets the name in the corresponding UMLObject. * Sets the local m_Text if m_umlObject is NULL. * * @param strName The name to be set. */ void WidgetBase::setName(const QString &strName) { if (m_umlObject) m_umlObject->setName(strName); else m_Text = strName; } /** * Returns text color * * @return currently used text color */ QColor WidgetBase::textColor() const { return m_textColor; } /** * Sets the text color * * @param color the new text color */ void WidgetBase::setTextColor(const QColor &color) { m_textColor = color; m_usesDiagramTextColor = false; } /** * Returns line color * * @return currently used line color */ QColor WidgetBase::lineColor() const { return m_lineColor; } /** * Sets the line color * * @param color The new line color */ void WidgetBase::setLineColor(const QColor &color) { m_lineColor = color; m_usesDiagramLineColor = false; } /** * Returns fill color * * @return currently used fill color */ QColor WidgetBase::fillColor() const { return m_fillColor; } /** * Sets the fill color * * @param color The new fill color */ void WidgetBase::setFillColor(const QColor &color) { m_fillColor = color; m_usesDiagramFillColor = false; } /** * Returns line width * * @return currently used line with */ uint WidgetBase::lineWidth() const { return m_lineWidth; } /** * Sets the line width * * @param width The new line width */ void WidgetBase::setLineWidth(uint width) { m_lineWidth = width; m_usesDiagramLineWidth = false; } /** * Return state of fill color usage * * @return True if fill color is used */ bool WidgetBase::useFillColor() { return m_useFillColor; } /** * Set state if fill color is used * * @param state The state to set */ void WidgetBase::setUseFillColor(bool state) { m_useFillColor = state; m_usesDiagramUseFillColor = false; } /** * Returns state if diagram text color is used * * @return True means diagram text color is used */ bool WidgetBase::usesDiagramTextColor() const { return m_usesDiagramTextColor; } /** * Set state if diagram text color is used * * @param state The state to set */ void WidgetBase::setUsesDiagramTextColor(bool state) { if (m_usesDiagramTextColor == state) { return; } m_usesDiagramTextColor = state; setTextColor(m_textColor); } /** * Returns state of diagram line color is used * * @return True means diagrams line color is used */ bool WidgetBase::usesDiagramLineColor() const { return m_usesDiagramLineColor; } /** * Set state of diagram line color is used * * @param state The state to set */ void WidgetBase::setUsesDiagramLineColor(bool state) { m_usesDiagramLineColor = state; } /** * Returns state of diagram fill color is used * * @return True means diagrams fill color is used */ bool WidgetBase::usesDiagramFillColor() const { return m_usesDiagramFillColor; } /** * Set state if diagram fill color is used * * @param state The state to set */ void WidgetBase::setUsesDiagramFillColor(bool state) { m_usesDiagramFillColor = state; } /** * Returns state of diagram use fill color is used * * @return True means diagrams fill color is used */ bool WidgetBase::usesDiagramUseFillColor() const { return m_usesDiagramUseFillColor; } /** * Set state of diagram use fill color is used * * @param state The state to set */ void WidgetBase::setUsesDiagramUseFillColor(bool state) { m_usesDiagramUseFillColor = state; } /** * Returns state of diagram line width is used * * @return True means diagrams line width is used */ bool WidgetBase::usesDiagramLineWidth() const { return m_usesDiagramLineWidth; } /** * Set state of diagram line width is used * * @param state The state to set */ void WidgetBase::setUsesDiagramLineWidth(bool state) { m_usesDiagramLineWidth = state; } /** * Returns the font used for diaplaying any text. * @return the font */ QFont WidgetBase::font() const { return m_font; } /** * Set the font used to display text inside this widget. */ void WidgetBase::setFont(const QFont& font) { m_font = font; } /** * Return state of auto resize property * @return the auto resize state */ bool WidgetBase::autoResize() { return m_autoResize; } /** * set auto resize state * @param state */ void WidgetBase::setAutoResize(bool state) { m_autoResize = state; } /** * Return changes state property * @return the changes shape state */ bool WidgetBase::changesShape() { return m_changesShape; } /** * set changes shape property * @param state */ void WidgetBase::setChangesShape(bool state) { m_changesShape = state; } /** * A virtual method for the widget to display a property dialog box. * Subclasses should reimplment this appropriately. * In case the user cancels the dialog or there are some requirements * not fulfilled the method returns false; true otherwise. * * @return true - properties has been applyed * @return false - properties has not been applied * */ bool WidgetBase::showPropertiesDialog() { return false; } /** * A virtual method to save the properties of this widget into a * QDomElement i.e xml. * * Subclasses should first create a new dedicated element as the child * of \a qElement parameter passed. Then this base method should be * called to save basic widget properties. * * @param qDoc A QDomDocument object representing the xml document. * @param qElement A QDomElement representing xml element data. */ void WidgetBase::saveToXMI1(QDomDocument& qDoc, QDomElement& qElement) { Q_UNUSED(qDoc) qElement.setAttribute(QLatin1String("textcolor"), m_usesDiagramTextColor ? QLatin1String("none") : m_textColor.name()); if (m_usesDiagramLineColor) { qElement.setAttribute(QLatin1String("linecolor"), QLatin1String("none")); } else { qElement.setAttribute(QLatin1String("linecolor"), m_lineColor.name()); } if (m_usesDiagramLineWidth) { qElement.setAttribute(QLatin1String("linewidth"), QLatin1String("none")); } else { qElement.setAttribute(QLatin1String("linewidth"), m_lineWidth); } qElement.setAttribute(QLatin1String("usefillcolor"), m_useFillColor); // for consistency the following attributes now use american spelling for "color" qElement.setAttribute(QLatin1String("usesdiagramfillcolor"), m_usesDiagramFillColor); qElement.setAttribute(QLatin1String("usesdiagramusefillcolor"), m_usesDiagramUseFillColor); if (m_usesDiagramFillColor) { qElement.setAttribute(QLatin1String("fillcolor"), QLatin1String("none")); } else { qElement.setAttribute(QLatin1String("fillcolor"), m_fillColor.name()); } qElement.setAttribute(QLatin1String("font"), m_font.toString()); qElement.setAttribute(QLatin1String("autoresize"), m_autoResize ? 1 : 0); } /** * A virtual method to load the properties of this widget from a * QDomElement into this widget. * * Subclasses should reimplement this to load addtional properties * required, calling this base method to load the basic properties of * the widget. * * @param qElement A QDomElement which contains xml info for this widget. * * @todo Add support to load older version. */ bool WidgetBase::loadFromXMI1(QDomElement& qElement) { // first load from "linecolour" and then overwrite with the "linecolor" // attribute if that one is present. The "linecolour" name was a "typo" in // earlier versions of Umbrello QString lineColor = qElement.attribute(QLatin1String("linecolour"), QLatin1String("none")); lineColor = qElement.attribute(QLatin1String("linecolor"), lineColor); if (lineColor != QLatin1String("none")) { setLineColor(QColor(lineColor)); m_usesDiagramLineColor = false; } else if (m_baseType != WidgetBase::wt_Box && m_scene != 0) { setLineColor(m_scene->lineColor()); m_usesDiagramLineColor = true; } QString lineWidth = qElement.attribute(QLatin1String("linewidth"), QLatin1String("none")); if (lineWidth != QLatin1String("none")) { setLineWidth(lineWidth.toInt()); m_usesDiagramLineWidth = false; } else if (m_scene) { setLineWidth(m_scene->lineWidth()); m_usesDiagramLineWidth = true; } QString textColor = qElement.attribute(QLatin1String("textcolor"), QLatin1String("none")); if (textColor != QLatin1String("none")) { m_textColor = QColor(textColor); m_usesDiagramTextColor = false; } else if (m_scene) { m_textColor = m_scene->textColor(); m_usesDiagramTextColor = true; } QString usefillcolor = qElement.attribute(QLatin1String("usefillcolor"), QLatin1String("1")); m_useFillColor = (bool)usefillcolor.toInt(); /* For the next three *color attributes, there was a mixup of american and english spelling for "color". So first we need to keep backward compatibility and try to retrieve the *colour attribute. Next we overwrite this value if we find a *color, otherwise the former *colour is kept. */ QString fillColor = qElement.attribute(QLatin1String("fillcolour"), QLatin1String("none")); fillColor = qElement.attribute(QLatin1String("fillcolor"), fillColor); if (fillColor != QLatin1String("none")) { m_fillColor = QColor(fillColor); } QString usesDiagramFillColor = qElement.attribute(QLatin1String("usesdiagramfillcolour"), QLatin1String("1")); usesDiagramFillColor = qElement.attribute(QLatin1String("usesdiagramfillcolor"), usesDiagramFillColor); m_usesDiagramFillColor = (bool)usesDiagramFillColor.toInt(); QString usesDiagramUseFillColor = qElement.attribute(QLatin1String("usesdiagramusefillcolour"), QLatin1String("1")); usesDiagramUseFillColor = qElement.attribute(QLatin1String("usesdiagramusefillcolor"), usesDiagramUseFillColor); m_usesDiagramUseFillColor = (bool)usesDiagramUseFillColor.toInt(); QString font = qElement.attribute(QLatin1String("font")); if (!font.isEmpty()) { QFont newFont; newFont.fromString(font); m_font = newFont; } else { uWarning() << "Using default font " << m_font.toString() << " for widget with xmi.id " << Uml::ID::toString(m_nId); } QString autoResize = qElement.attribute(QLatin1String("autoresize"), QLatin1String("1")); m_autoResize = (bool)autoResize.toInt(); return true; } /** * Assignment operator */ WidgetBase& WidgetBase::operator=(const WidgetBase& other) { m_baseType = other.m_baseType; m_scene = other.m_scene; m_umlObject = other.m_umlObject; m_Doc = other.m_Doc; m_Text = other.m_Text; m_nId = other.m_nId; m_textColor = other.m_textColor; setLineColor(other.lineColor()); m_fillColor = other.m_fillColor; m_brush = other.m_brush; m_font = other.m_font; m_lineWidth = other.m_lineWidth; m_useFillColor = other.m_useFillColor; m_usesDiagramTextColor = other.m_usesDiagramTextColor; m_usesDiagramLineColor = other.m_usesDiagramLineColor; m_usesDiagramFillColor = other.m_usesDiagramFillColor; m_usesDiagramLineWidth = other.m_usesDiagramLineWidth; setSelected(other.isSelected()); return *this; } /** * return drawing rectangle of widget in local coordinates */ QRectF WidgetBase::rect() const { return m_rect; } /** * set widget rectangle in item coordinates */ void WidgetBase::setRect(const QRectF& rect) { if (m_rect == rect) return; prepareGeometryChange(); m_rect = rect; update(); } /** * set widget rectangle in item coordinates */ void WidgetBase::setRect(qreal x, qreal y, qreal width, qreal height) { setRect(QRectF(x, y, width, height)); } /** * @return The bounding rectangle for this widget. * @see setRect */ QRectF WidgetBase::boundingRect() const { int halfWidth = lineWidth()/2; return m_rect.adjusted(-halfWidth, -halfWidth, halfWidth, halfWidth); } /** * Test if point is inside the bounding rectangle of the widget. * Inheriting classes may reimplement this to test possible child widgets. * * @param p Point to be checked. * * @return 'this' if the given point is in the boundaries of the widget; * else NULL. */ UMLWidget* WidgetBase::onWidget(const QPointF &p) { UMLWidget *uw = this->asUMLWidget(); if (uw == 0) return 0; const qreal w = m_rect.width(); const qreal h = m_rect.height(); const qreal left = x(); // don't use m_rect.x() for this, it is always 0 const qreal right = left + w; const qreal top = y(); // don't use m_rect.y() for this, it is always 0 const qreal bottom = top + h; // uDebug() << "p=(" << p.x() << "," << p.y() // << "), x=" << left << ", y=" << top << ", w=" << w << ", h=" << h // << "; right=" << right << ", bottom=" << bottom; if (p.x() < left || p.x() > right || p.y() < top || p.y() > bottom) { // Qt coord.sys. origin in top left corner // uDebug() << "returning NULL"; return 0; } // uDebug() << "returning this"; return uw; } /** * Draws the UMLWidget on the given paint device * * @param painter The painter for the drawing device * @param option Painting related options * @param widget Background widget on which to paint (optional) * */ void WidgetBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(painter); Q_UNUSED(option); Q_UNUSED(widget); } /** * Reimplemented to show appropriate context menu. */ void WidgetBase::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { event->accept(); uDebug() << "widget = " << name() << " / type = " << baseTypeStr(); UMLScene *scene = umlScene(); // If right-click was done on a widget that was not selected, clear the // current selection and select the new widget. The context menu is shown // with actions for that single widget. // If a keyboard modifier was used, add the widget to the current selection // and show the menu with actions for the whole selection. if (!isSelected()) { Qt::KeyboardModifiers forSelection = (Qt::ControlModifier | Qt::ShiftModifier); if ((event->modifiers() & forSelection) == 0) { scene->clearSelected(); } if (umlObject() != 0) { scene->selectWidget(this->asUMLWidget()); } else { setSelected(true); } } int count = scene->selectedCount(true); // Determine multi state bool multi = (isSelected() && count > 1); WidgetBasePopupMenu popup(0, this, multi, scene->getUniqueSelectionType()); // Disable the "view code" menu for simple code generators if (UMLApp::app()->isSimpleCodeGeneratorActive()) { popup.setActionEnabled(ListPopupMenu::mt_ViewCode, false); } QAction *triggered = popup.exec(event->screenPos()); slotMenuSelection(triggered); } /** * This is usually called synchronously after menu.exec() and \a * trigger's parent is always the ListPopupMenu which can be used to * get the type of action of \a trigger. * * @note Subclasses can reimplement to handle specific actions and * leave the rest to WidgetBase::slotMenuSelection. */ void WidgetBase::slotMenuSelection(QAction *trigger) { if (!trigger) { return; } QColor newColor; const WidgetType wt = m_baseType; // short hand name ListPopupMenu::MenuType sel = ListPopupMenu::typeFromAction(trigger); switch (sel) { case ListPopupMenu::mt_Rename: umlDoc()->renameUMLObject(umlObject()); break; case ListPopupMenu::mt_Properties: if (wt == WidgetBase::wt_Actor || wt == WidgetBase::wt_UseCase || wt == WidgetBase::wt_Package || wt == WidgetBase::wt_Interface || wt == WidgetBase::wt_Datatype || wt == WidgetBase::wt_Node || wt == WidgetBase::wt_Component || wt == WidgetBase::wt_Artifact || wt == WidgetBase::wt_Enum || wt == WidgetBase::wt_Entity || wt == WidgetBase::wt_Port || wt == WidgetBase::wt_Instance || (wt == WidgetBase::wt_Class && umlScene()->type() == Uml::DiagramType::Class)) { showPropertiesDialog(); } else if (wt == WidgetBase::wt_Object) { m_umlObject->showPropertiesDialog(); } else { uWarning() << "making properties dialog for unknown widget type"; } break; case ListPopupMenu::mt_Line_Color: case ListPopupMenu::mt_Line_Color_Selection: #if QT_VERSION >= 0x050000 newColor = QColorDialog::getColor(lineColor()); if (newColor != lineColor()) { #else newColor = lineColor(); if (KColorDialog::getColor(newColor)) { #endif if (sel == ListPopupMenu::mt_Line_Color_Selection) { umlScene()->selectionSetLineColor(newColor); } else { setLineColor(newColor); } setUsesDiagramLineColor(false); umlDoc()->setModified(true); } break; case ListPopupMenu::mt_Fill_Color: case ListPopupMenu::mt_Fill_Color_Selection: #if QT_VERSION >= 0x050000 newColor = QColorDialog::getColor(fillColor()); if (newColor != fillColor()) { #else newColor = fillColor(); if (KColorDialog::getColor(newColor)) { #endif if (sel == ListPopupMenu::mt_Fill_Color_Selection) { umlScene()->selectionSetFillColor(newColor); } else { setFillColor(newColor); } umlDoc()->setModified(true); } break; case ListPopupMenu::mt_Use_Fill_Color: setUseFillColor(!m_useFillColor); break; case ListPopupMenu::mt_Set_Use_Fill_Color_Selection: umlScene()->selectionUseFillColor(true); break; case ListPopupMenu::mt_Unset_Use_Fill_Color_Selection: umlScene()->selectionUseFillColor(false); break; case ListPopupMenu::mt_Show_Attributes_Selection: case ListPopupMenu::mt_Hide_Attributes_Selection: umlScene()->selectionSetVisualProperty( ClassifierWidget::ShowAttributes, sel != ListPopupMenu::mt_Hide_Attributes_Selection ); break; case ListPopupMenu::mt_Show_Operations_Selection: case ListPopupMenu::mt_Hide_Operations_Selection: umlScene()->selectionSetVisualProperty( ClassifierWidget::ShowOperations, sel != ListPopupMenu::mt_Hide_Operations_Selection ); break; case ListPopupMenu::mt_Show_Visibility_Selection: case ListPopupMenu::mt_Hide_Visibility_Selection: umlScene()->selectionSetVisualProperty( ClassifierWidget::ShowVisibility, sel != ListPopupMenu::mt_Hide_Visibility_Selection ); break; case ListPopupMenu::mt_Show_Operation_Signature_Selection: case ListPopupMenu::mt_Hide_Operation_Signature_Selection: umlScene()->selectionSetVisualProperty( ClassifierWidget::ShowOperationSignature, sel != ListPopupMenu::mt_Hide_Operation_Signature_Selection ); break; case ListPopupMenu::mt_Show_Attribute_Signature_Selection: case ListPopupMenu::mt_Hide_Attribute_Signature_Selection: umlScene()->selectionSetVisualProperty( ClassifierWidget::ShowAttributeSignature, sel != ListPopupMenu::mt_Hide_Attribute_Signature_Selection ); break; case ListPopupMenu::mt_Show_Packages_Selection: case ListPopupMenu::mt_Hide_Packages_Selection: umlScene()->selectionSetVisualProperty( ClassifierWidget::ShowPackage, sel != ListPopupMenu::mt_Hide_Packages_Selection ); break; case ListPopupMenu::mt_Show_Stereotypes_Selection: case ListPopupMenu::mt_Hide_Stereotypes_Selection: umlScene()->selectionSetVisualProperty( ClassifierWidget::ShowStereotype, sel != ListPopupMenu::mt_Hide_Stereotypes_Selection ); break; case ListPopupMenu::mt_Hide_NonPublic_Selection: case ListPopupMenu::mt_Show_NonPublic_Selection: umlScene()->selectionSetVisualProperty( ClassifierWidget::ShowPublicOnly, sel != ListPopupMenu::mt_Show_NonPublic_Selection ); break; case ListPopupMenu::mt_ViewCode: { UMLClassifier *c = umlObject()->asUMLClassifier(); if (c) { UMLApp::app()->viewCodeDocument(c); } break; } case ListPopupMenu::mt_Remove: umlScene()->deleteSelection(); break; case ListPopupMenu::mt_Delete: if (!Dialog_Utils::askDeleteAssociation()) break; umlScene()->deleteSelection(); break; case ListPopupMenu::mt_Change_Font: case ListPopupMenu::mt_Change_Font_Selection: { #if QT_VERSION >= 0x050000 bool ok = false; QFont newFont = QFontDialog::getFont(&ok, font()); if (ok) { #else QFont newFont = font(); if (KFontDialog::getFont(newFont, KFontChooser::NoDisplayFlags, 0) == KFontDialog::Accepted) { #endif if (sel == ListPopupMenu::mt_Change_Font_Selection) { m_scene->selectionSetFont(newFont); } else { setFont(newFont); } } } break; case ListPopupMenu::mt_Cut: umlScene()->setStartedCut(); UMLApp::app()->slotEditCut(); break; case ListPopupMenu::mt_Copy: UMLApp::app()->slotEditCopy(); break; case ListPopupMenu::mt_Paste: UMLApp::app()->slotEditPaste(); break; case ListPopupMenu::mt_Refactoring: //check if we are operating on a classifier, or some other kind of UMLObject if (umlObject()->asUMLClassifier()) { UMLApp::app()->refactor(umlObject()->asUMLClassifier()); } break; case ListPopupMenu::mt_Clone: { foreach (UMLWidget* widget, umlScene()->selectedWidgets()) { if (Model_Utils::isCloneable(widget->baseType())) { UMLObject *clone = widget->umlObject()->clone(); umlScene()->addObject(clone); } } } break; case ListPopupMenu::mt_Rename_MultiA: case ListPopupMenu::mt_Rename_MultiB: case ListPopupMenu::mt_Rename_Name: case ListPopupMenu::mt_Rename_RoleAName: case ListPopupMenu::mt_Rename_RoleBName: { FloatingTextWidget *ft = static_cast(this); ft->handleRename(); break; } case ListPopupMenu::mt_Align_Right: umlScene()->alignRight(); break; case ListPopupMenu::mt_Align_Left: umlScene()->alignLeft(); break; case ListPopupMenu::mt_Align_Top: umlScene()->alignTop(); break; case ListPopupMenu::mt_Align_Bottom: umlScene()->alignBottom(); break; case ListPopupMenu::mt_Align_VerticalMiddle: umlScene()->alignVerticalMiddle(); break; case ListPopupMenu::mt_Align_HorizontalMiddle: umlScene()->alignHorizontalMiddle(); break; case ListPopupMenu::mt_Align_VerticalDistribute: umlScene()->alignVerticalDistribute(); break; case ListPopupMenu::mt_Align_HorizontalDistribute: umlScene()->alignHorizontalDistribute(); break; default: uDebug() << "MenuType " << ListPopupMenu::toString(sel) << " not implemented"; break; } } /** * Helper function for debug output. * Returns the given enum value as string. * @param wt WidgetType of which a string representation is wanted * @return the WidgetType as string */ QString WidgetBase::toString(WidgetType wt) { return QLatin1String(ENUM_NAME(WidgetBase, WidgetType, wt)); } /** * Returns the given enum value as localized string. * @param wt WidgetType of which a string representation is wanted * @return the WidgetType as localized string */ QString WidgetBase::toI18nString(WidgetType wt) { QString name; switch (wt) { case wt_Activity: name = i18n("Activity"); break; case wt_Actor: name = i18n("Actor"); break; case wt_Artifact: name = i18n("Artifact"); break; case wt_Association: name = i18n("Association"); break; case wt_Box: name = i18n("Box"); break; case wt_Category: name = i18n("Category"); break; case wt_CombinedFragment: name = i18n("CombinedFragment"); break; case wt_Component: name = i18n("Component"); break; case wt_Class: name = i18n("Class"); break; case wt_Datatype: name = i18n("Datatype"); break; case wt_Entity: name = i18n("Entity"); break; case wt_Enum: name = i18n("Enum"); break; case wt_FloatingDashLine: name = i18n("FloatingDashLine"); break; case wt_ForkJoin: name = i18n("ForkJoin"); break; case wt_Interface: name = i18n("Interface"); break; case wt_Message: name = i18n("Message"); break; case wt_Node: name = i18n("Node"); break; case wt_Note: name = i18n("Note"); break; case wt_Object: name = i18n("Object"); break; case wt_ObjectNode: name = i18n("ObjectNode"); break; case wt_Package: name = i18n("Package"); break; case wt_Pin: name = i18n("Pin"); break; case wt_Port: name = i18n("Port"); break; case wt_Precondition: name = i18n("Precondition"); break; case wt_Region: name = i18n("Region"); break; case wt_Signal: name = i18n("Signal"); break; case wt_State: name = i18n("State"); break; case wt_Text: name = i18n("Text"); break; case wt_UseCase: name = i18n("UseCase"); break; case wt_Instance: name = i18n("Instance"); break; default: name = QLatin1String(" &name:"); uWarning() << "unknown widget type"; break; } return name; } /** * Returns the given enum value as icon type. * @param wt WidgetType of which an icon type representation is wanted * @return the WidgetType as icon type */ Icon_Utils::IconType WidgetBase::toIcon(WidgetBase::WidgetType wt) { Icon_Utils::IconType icon; switch (wt) { case wt_Activity: icon = Icon_Utils::it_Activity; break; case wt_Actor: icon = Icon_Utils::it_Actor; break; case wt_Artifact: icon = Icon_Utils::it_Artifact; break; case wt_Association: icon = Icon_Utils::it_Association; break; case wt_Box: icon = Icon_Utils::it_Box; break; case wt_Category: icon = Icon_Utils::it_Category; break; case wt_CombinedFragment: icon = Icon_Utils::it_Combined_Fragment; break; case wt_Component: icon = Icon_Utils::it_Component; break; case wt_Class: icon = Icon_Utils::it_Class; break; case wt_Datatype: icon = Icon_Utils::it_Datatype; break; case wt_Entity: icon = Icon_Utils::it_Entity; break; case wt_Enum: icon = Icon_Utils::it_Enum; break; case wt_FloatingDashLine: icon = Icon_Utils::it_Association; break; case wt_ForkJoin: icon = Icon_Utils::it_Fork_Join; break; case wt_Instance: icon = Icon_Utils::it_Instance; break; case wt_Interface: icon = Icon_Utils::it_Interface; break; case wt_Message: icon = Icon_Utils::it_Message_Synchronous; break; case wt_Node: icon = Icon_Utils::it_Node; break; case wt_Note: icon = Icon_Utils::it_Note; break; case wt_Object: icon = Icon_Utils::it_Object; break; case wt_ObjectNode: icon = Icon_Utils::it_Object_Node; break; case wt_Package: icon = Icon_Utils::it_Package; break; case wt_Pin: icon = Icon_Utils::it_Pin; break; case wt_Port: icon = Icon_Utils::it_Port; break; case wt_Precondition: icon = Icon_Utils::it_Precondition; break; case wt_Region: icon = Icon_Utils::it_Region; break; case wt_Signal: icon = Icon_Utils::it_Send_Signal; break; case wt_State: icon = Icon_Utils::it_State; break; case wt_Text: icon = Icon_Utils::it_Text; break; case wt_UseCase: icon = Icon_Utils::it_UseCase; break; default: icon = Icon_Utils::it_Home; uWarning() << "unknown widget type"; break; } return icon; } #include "activitywidget.h" #include "actorwidget.h" #include "artifactwidget.h" #include "associationwidget.h" #include "boxwidget.h" #include "categorywidget.h" //#include "classwidget.h" #include "combinedfragmentwidget.h" #include "componentwidget.h" #include "datatypewidget.h" #include "entitywidget.h" #include "enumwidget.h" #include "floatingdashlinewidget.h" #include "forkjoinwidget.h" -//#include "interfacewidget.h" +#include "interfacewidget.h" #include "messagewidget.h" #include "nodewidget.h" #include "notewidget.h" #include "objectnodewidget.h" #include "objectwidget.h" #include "packagewidget.h" #include "pinwidget.h" #include "portwidget.h" #include "preconditionwidget.h" #include "regionwidget.h" #include "signalwidget.h" #include "statewidget.h" #include "usecasewidget.h" ActivityWidget* WidgetBase::asActivityWidget() { return dynamic_cast(this); } ActorWidget* WidgetBase::asActorWidget() { return dynamic_cast(this); } ArtifactWidget* WidgetBase::asArtifactWidget() { return dynamic_cast(this); } AssociationWidget* WidgetBase::asAssociationWidget() { return dynamic_cast(this); } BoxWidget* WidgetBase::asBoxWidget() { return dynamic_cast(this); } CategoryWidget* WidgetBase::asCategoryWidget() { return dynamic_cast(this); } ClassifierWidget* WidgetBase::asClassifierWidget() { return dynamic_cast(this); } CombinedFragmentWidget* WidgetBase::asCombinedFragmentWidget() { return dynamic_cast(this); } ComponentWidget* WidgetBase::asComponentWidget() { return dynamic_cast(this); } DatatypeWidget* WidgetBase::asDatatypeWidget() { return dynamic_cast(this); } EntityWidget* WidgetBase::asEntityWidget() { return dynamic_cast(this); } EnumWidget* WidgetBase::asEnumWidget() { return dynamic_cast(this); } FloatingDashLineWidget* WidgetBase::asFloatingDashLineWidget() { return dynamic_cast(this); } ForkJoinWidget* WidgetBase::asForkJoinWidget() { return dynamic_cast(this); } -//InterfaceWidget* WidgetBase::asInterfaceWidget() { return dynamic_cast(this); } +InterfaceWidget* WidgetBase::asInterfaceWidget() { return dynamic_cast(this); } MessageWidget* WidgetBase::asMessageWidget() { return dynamic_cast(this); } NodeWidget* WidgetBase::asNodeWidget() { return dynamic_cast(this); } NoteWidget* WidgetBase::asNoteWidget() { return dynamic_cast(this); } ObjectNodeWidget* WidgetBase::asObjectNodeWidget() { return dynamic_cast(this); } ObjectWidget* WidgetBase::asObjectWidget() { return dynamic_cast(this); } PackageWidget* WidgetBase::asPackageWidget() { return dynamic_cast(this); } PinWidget* WidgetBase::asPinWidget() { return dynamic_cast(this); } PinPortBase *WidgetBase::asPinPortBase() { return dynamic_cast(this); } PortWidget* WidgetBase::asPortWidget() { return dynamic_cast(this); } PreconditionWidget* WidgetBase::asPreconditionWidget() { return dynamic_cast(this); } RegionWidget* WidgetBase::asRegionWidget() { return dynamic_cast(this); } SignalWidget* WidgetBase::asSignalWidget() { return dynamic_cast(this); } StateWidget* WidgetBase::asStateWidget() { return dynamic_cast(this); } FloatingTextWidget* WidgetBase::asFloatingTextWidget() { return dynamic_cast(this); } //TextWidget* WidgetBase::asTextWidget() { return dynamic_cast(this); } UseCaseWidget* WidgetBase::asUseCaseWidget() { return dynamic_cast(this); } UMLWidget *WidgetBase::asUMLWidget() { return dynamic_cast(this); } diff --git a/umbrello/umlwidgets/widgetbase.h b/umbrello/umlwidgets/widgetbase.h index 4e27b7906..ce668ba19 100644 --- a/umbrello/umlwidgets/widgetbase.h +++ b/umbrello/umlwidgets/widgetbase.h @@ -1,303 +1,303 @@ /*************************************************************************** * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * copyright (C) 2004-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ #ifndef WIDGETBASE_H #define WIDGETBASE_H #include "basictypes.h" #include "icon_utils.h" #include #include #include #include #include #include #include // forward declarations class QAction; class ActivityWidget; class ActorWidget; class ArtifactWidget; class AssociationWidget; class BoxWidget; class CategoryWidget; class ClassifierWidget; class CombinedFragmentWidget; class ComponentWidget; class DatatypeWidget; class EntityWidget; class EnumWidget; class FloatingDashLineWidget; class FloatingTextWidget; class ForkJoinWidget; -//class InterfaceWidget; +class InterfaceWidget; class MessageWidget; class NodeWidget; class NoteWidget; class ObjectNodeWidget; class ObjectWidget; class PackageWidget; class PinWidget; class PortWidget; class PinPortBase; class PreconditionWidget; class RegionWidget; class SignalWidget; class StateWidget; //class TextWidget; class UseCaseWidget; class UMLDoc; class UMLObject; class UMLScene; class UMLWidget; // required by function onWidget() /** * @short Common base class for UMLWidget and AssociationWidget * @author Oliver Kellogg * Bugs and comments to umbrello-devel@kde.org or http://bugs.kde.org */ class WidgetBase : public QGraphicsObject { Q_OBJECT Q_ENUMS(WidgetType) public: enum WidgetType { wt_Min = 299, // lower bounds check value wt_UMLWidget, // does not have UMLObject representation wt_Actor, // has UMLObject representation wt_UseCase, // has UMLObject representation wt_Class, // has UMLObject representation wt_Interface, // has UMLObject representation wt_Datatype, // has UMLObject representation wt_Enum, // has UMLObject representation wt_Entity, // has UMLObject representation wt_Package, // has UMLObject representation wt_Object, // has UMLObject representation wt_Note, // does not have UMLObject representation wt_Box, // does not have UMLObject representation wt_Message, // does not have UMLObject representation wt_Text, // does not have UMLObject representation wt_State, // does not have UMLObject representation wt_Activity, // does not have UMLObject representation wt_Component, // has UMLObject representation wt_Artifact, // has UMLObject representation wt_Node, // has UMLObject representation wt_Association, // has UMLObject representation wt_ForkJoin, // does not have UMLObject representation wt_Precondition, // does not have UMLObject representation wt_CombinedFragment, // does not have UMLObject representation wt_FloatingDashLine, // does not have UMLObject representation wt_Signal, // does not have UMLObject representation wt_Pin, wt_ObjectNode, wt_Region, wt_Category, // has UMLObject representation wt_Port, // has UMLObject representation wt_Instance, // has UMLObject representation == wt_Object wt_Max // upper bounds check value }; static QString toString(WidgetType wt); static QString toI18nString(WidgetType wt); static Icon_Utils::IconType toIcon(WidgetType wt); explicit WidgetBase(UMLScene * scene, WidgetType type= wt_UMLWidget); virtual ~WidgetBase(); UMLObject* umlObject() const; virtual void setUMLObject(UMLObject *obj); Uml::ID::Type id() const; void setID(Uml::ID::Type id); WidgetType baseType() const; void setBaseType(const WidgetType& baseType); QLatin1String baseTypeStr() const; virtual void setSelected(bool select); UMLScene* umlScene() const; UMLDoc* umlDoc() const; QString documentation() const; bool hasDocumentation(); virtual void setDocumentation(const QString& doc); QString name() const; virtual void setName(const QString &strName); QColor lineColor() const; virtual void setLineColor(const QColor& color); uint lineWidth() const; virtual void setLineWidth(uint width); QColor textColor() const; virtual void setTextColor(const QColor& color); QColor fillColor() const; virtual void setFillColor(const QColor& color); bool usesDiagramLineColor() const; void setUsesDiagramLineColor(bool state); bool usesDiagramLineWidth() const; void setUsesDiagramLineWidth(bool state); bool useFillColor(); virtual void setUseFillColor(bool state); bool usesDiagramTextColor() const; void setUsesDiagramTextColor(bool state); bool usesDiagramFillColor() const; void setUsesDiagramFillColor(bool state); bool usesDiagramUseFillColor() const; void setUsesDiagramUseFillColor(bool state); virtual QFont font() const; virtual void setFont(const QFont& font); bool autoResize(); void setAutoResize(bool state); bool changesShape(); void setChangesShape(bool state); virtual bool showPropertiesDialog(); virtual bool loadFromXMI1(QDomElement &qElement); virtual void saveToXMI1(QDomDocument &qDoc, QDomElement &qElement); WidgetBase& operator=(const WidgetBase& other); QRectF rect() const; void setRect(const QRectF& rect); void setRect(qreal x, qreal y, qreal width, qreal height); virtual QRectF boundingRect() const; virtual UMLWidget* onWidget(const QPointF &p); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); bool isActivityWidget() { return baseType() == wt_Activity; } bool isActorWidget() { return baseType() == wt_Actor; } bool isArtifactWidget() { return baseType() == wt_Artifact; } bool isAssociationWidget() { return baseType() == wt_Association; } bool isBoxWidget() { return baseType() == wt_Box; } bool isCategoryWidget() { return baseType() == wt_Category; } bool isClassWidget() { return baseType() == wt_Class; } bool isCombinedFragmentWidget() { return baseType() == wt_CombinedFragment; } bool isComponentWidget() { return baseType() == wt_Component; } bool isDatatypeWidget() { return baseType() == wt_Datatype; } bool isEntityWidget() { return baseType() == wt_Entity; } bool isEnumWidget() { return baseType() == wt_Enum; } bool isFloatingDashLineWidget() { return baseType() == wt_FloatingDashLine; } bool isForkJoinWidget() { return baseType() == wt_ForkJoin; } bool isInterfaceWidget() { return baseType() == wt_Interface; } bool isMessageWidget() { return baseType() == wt_Message; } bool isNodeWidget() { return baseType() == wt_Node; } bool isNoteWidget() { return baseType() == wt_Note; } bool isObjectNodeWidget() { return baseType() == wt_ObjectNode; } bool isObjectWidget() { return baseType() == wt_Object; } bool isPackageWidget() { return baseType() == wt_Package; } bool isPinWidget() { return baseType() == wt_Pin; } bool isPortWidget() { return baseType() == wt_Port; } bool isPreconditionWidget() { return baseType() == wt_Precondition; } bool isRegionWidget() { return baseType() == wt_Region; } bool isSignalWidget() { return baseType() == wt_Signal; } bool isStateWidget() { return baseType() == wt_State; } bool isTextWidget() { return baseType() == wt_Text; } bool isUseCaseWidget() { return baseType() == wt_UseCase; } ActivityWidget* asActivityWidget(); ActorWidget* asActorWidget(); ArtifactWidget* asArtifactWidget(); AssociationWidget* asAssociationWidget(); BoxWidget* asBoxWidget(); CategoryWidget* asCategoryWidget(); ClassifierWidget* asClassifierWidget(); CombinedFragmentWidget* asCombinedFragmentWidget(); ComponentWidget* asComponentWidget(); DatatypeWidget* asDatatypeWidget(); EntityWidget* asEntityWidget(); EnumWidget* asEnumWidget(); FloatingDashLineWidget* asFloatingDashLineWidget(); ForkJoinWidget* asForkJoinWidget(); - //InterfaceWidget* asInterfaceWidget(); + InterfaceWidget* asInterfaceWidget(); MessageWidget* asMessageWidget(); NodeWidget* asNodeWidget(); NoteWidget* asNoteWidget(); ObjectNodeWidget* asObjectNodeWidget(); ObjectWidget* asObjectWidget(); PackageWidget* asPackageWidget(); PinWidget* asPinWidget(); PinPortBase* asPinPortBase(); PortWidget* asPortWidget(); PreconditionWidget* asPreconditionWidget(); RegionWidget* asRegionWidget(); SignalWidget* asSignalWidget(); StateWidget* asStateWidget(); FloatingTextWidget* asFloatingTextWidget(); // TextWidget* asTextWidget(); UseCaseWidget* asUseCaseWidget(); UMLWidget* asUMLWidget(); public Q_SLOTS: virtual void slotMenuSelection(QAction *trigger); protected: virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); private: WidgetType m_baseType; ///< Type of widget. protected: UMLScene *m_scene; QPointer m_umlObject; QString m_Doc; ///< Only used if m_umlObject is not set. QString m_Text; QRectF m_rect; ///< widget size /** * This ID is only used when the widget does not have a * corresponding UMLObject (i.e. the m_umlObject pointer is NULL.) * For UMLObjects, the ID from the UMLObject is used. */ Uml::ID::Type m_nId; QColor m_textColor; ///< Color of the text of the widget. Is saved to XMI. QColor m_lineColor; ///< Color of the lines of the widget. Is saved to XMI. QColor m_fillColor; ///< color of the background of the widget QBrush m_brush; QFont m_font; uint m_lineWidth; ///< Width of the lines of the widget. Is saved to XMI. bool m_useFillColor; ///< flag indicates if the UMLWidget uses the Diagram FillColour /** * true by default, false if the colors have * been explicitly set for this widget. * These are saved to XMI. */ bool m_usesDiagramFillColor; bool m_usesDiagramLineColor; bool m_usesDiagramLineWidth; bool m_usesDiagramTextColor; bool m_usesDiagramUseFillColor; bool m_autoResize; bool m_changesShape; ///< The widget changes its shape when the number of connections or their positions are changed }; #endif diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 5934a62f1..e8e55e0f8 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -1,156 +1,156 @@ set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) set(SRC_PATH ../umbrello) include_directories( ${LIBXML2_INCLUDE_DIR} ${LIBXSLT_INCLUDE_DIR} ${CMAKE_SOURCE_DIR} ${SRC_PATH} ${SRC_PATH}/debug/ ${SRC_PATH}/dialogs/ ${SRC_PATH}/dialogs/pages ${SRC_PATH}/dialogs/widgets ${SRC_PATH}/clipboard ${SRC_PATH}/cmds ${SRC_PATH}/codegenerators ${SRC_PATH}/codegenerators/ada/ ${SRC_PATH}/codegenerators/as/ ${SRC_PATH}/codegenerators/cpp/ ${SRC_PATH}/codegenerators/csharp/ ${SRC_PATH}/codegenerators/d/ ${SRC_PATH}/codegenerators/idl/ ${SRC_PATH}/codegenerators/java/ ${SRC_PATH}/codegenerators/js/ ${SRC_PATH}/codegenerators/pascal/ ${SRC_PATH}/codegenerators/perl/ ${SRC_PATH}/codegenerators/php/ ${SRC_PATH}/codegenerators/python/ ${SRC_PATH}/codegenerators/ruby/ ${SRC_PATH}/codegenerators/sql/ ${SRC_PATH}/codegenerators/tcl/ ${SRC_PATH}/codegenerators/vala/ ${SRC_PATH}/codegenerators/xml/ ${SRC_PATH}/codegenwizard ${SRC_PATH}/codeimport ${SRC_PATH}/debug ${SRC_PATH}/dialogs ${SRC_PATH}/docgenerators ${SRC_PATH}/menus/ ${SRC_PATH}/refactoring ${SRC_PATH}/uml1model/ ${SRC_PATH}/umlwidgets/ ${CMAKE_CURRENT_BINARY_DIR} ) if(NOT BUILD_KF5) set(LIBS Qt4::QtCore Qt4::QtGui Qt4::QtXml Qt4::QtTest Qt4::QtWebKit ${KDE4_KFILE_LIBS} ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} libumbrello ) else() set(LIBS Qt5::Xml Qt5::Test Qt5::Widgets Qt5::WebKitWidgets KF5::I18n KF5::Crash ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} libumbrello ) endif() ecm_add_test( testbasictypes.cpp LINK_LIBRARIES ${LIBS} TEST_NAME testbasictypes ) ecm_add_test( testumlobject.cpp testbase.cpp LINK_LIBRARIES ${LIBS} TEST_NAME testumlobject ) #ecm_add_test( # testclassifier.cpp # testbase.cpp # LINK_LIBRARIES ${LIBS} # TEST_NAME testclassifier #) ecm_add_test( testcppwriter.cpp testbase.cpp LINK_LIBRARIES ${LIBS} TEST_NAME testcppwriter ) ecm_add_test( testpythonwriter.cpp testbase.cpp LINK_LIBRARIES ${LIBS} TEST_NAME testpythonwriter ) ecm_add_test( testoptionstate.cpp testbase.cpp LINK_LIBRARIES ${LIBS} TEST_NAME testoptionstate ) set(testumlroledialog_SRCS testumlroledialog.cpp ) -ecm_add_executable(testumlroledialog ${testumlroledialog_SRCS}) +add_executable(testumlroledialog ${testumlroledialog_SRCS}) target_link_libraries(testumlroledialog ${LIBS}) -ecm_add_executable(testcrashhandler testcrashhandler.cpp) +add_executable(testcrashhandler testcrashhandler.cpp) target_link_libraries(testcrashhandler ${LIBS}) -ecm_add_executable(testlistpopupmenu testlistpopupmenu.cpp testbase.cpp) +add_executable(testlistpopupmenu testlistpopupmenu.cpp testbase.cpp) target_link_libraries(testlistpopupmenu ${LIBS}) find_package(LLVM CONFIG) find_package(CLANG QUIET) if(LLVM_FOUND AND CLANG_FOUND) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") message(STATUS "Found CLANG ${CLANG_PACKAGE_VERSION}") include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) include_directories(${CLANG_INCLUDE_DIRS}) add_definitions(${CLANG_DEFINITIONS}) # Now build our tools add_executable(testllvm testllvm.cpp) # Find the libraries that correspond to the LLVM components # that we wish to use llvm_map_components_to_libnames(llvm_libs support core irreader analysis) # Link against LLVM libraries target_link_libraries(testllvm ${llvm_libs} clangFrontend clangTooling) add_executable(testllvmparser testllvmparser.cpp) llvm_map_components_to_libnames(llvm_libs support) target_link_libraries(testllvmparser ${llvm_libs} clangFrontend clangTooling clangAST clangBasic ${LIBS}) ecm_mark_nongui_executable(testllvm testllvmparser) endif() add_custom_target(check COMMAND ${CMAKE_BUILD_TOOL} test)