Commit 40e7e2cc authored by Eike Ziller's avatar Eike Ziller

Merge remote-tracking branch 'origin/master' into 4.0

Change-Id: If8d27122d8015700da6684538d01958e9dd2da80
parents 08457143 c3a1355c
include(../../qtcreatorlibrary.pri)
QT += svg
DEFINES += QMT_LIBRARY
INCLUDEPATH += $$PWD $$PWD/qtserialization/inc
......
......@@ -9,7 +9,7 @@ QtcLibrary {
"./qtserialization/inc",
])
Depends { name: "Qt.widgets" }
Depends { name: "Qt"; submodules: ["widgets", "svg"] }
Depends { name: "Utils" }
Group {
......
......@@ -57,10 +57,9 @@
#include <QBuffer>
#include <QPdfWriter>
#include <QFile>
#ifdef USE_SVG_CLIPBOARD
#include <QtSvg/QSvgGenerator>
#endif
namespace qmt {
......@@ -372,6 +371,8 @@ void DiagramSceneModel::copyToClipboard()
#ifdef USE_SVG_CLIPBOARD
{
const double border = 5;
QBuffer svgBuffer;
QSvgGenerator svgGenerator;
svgGenerator.setOutputDevice(&svgBuffer);
......@@ -383,8 +384,8 @@ void DiagramSceneModel::copyToClipboard()
svgPainter.setRenderHint(QPainter::Antialiasing);
m_graphicsScene->render(&svgPainter,
QRectF(border, border,
painter.device()->width() - 2 * border,
painter.device()->height() - 2 * border),
svgPainter.device()->width() - 2 * border,
svgPainter.device()->height() - 2 * border),
sceneBoundingRect);
svgPainter.end();
mimeData->setData(QStringLiteral("image/svg+xml"), svgBuffer.buffer());
......@@ -414,8 +415,9 @@ void DiagramSceneModel::copyToClipboard()
}
}
bool DiagramSceneModel::exportPng(const QString &fileName)
bool DiagramSceneModel::exportImage(const QString &fileName)
{
// TODO support exporting selected elements only
removeExtraSceneItems();
QRectF sceneBoundingRect = m_graphicsScene->itemsBoundingRect();
......@@ -450,8 +452,9 @@ bool DiagramSceneModel::exportPng(const QString &fileName)
return success;
}
void DiagramSceneModel::exportPdf(const QString &fileName)
bool DiagramSceneModel::exportPdf(const QString &fileName)
{
// TODO support exporting selected elements only
removeExtraSceneItems();
QRectF sceneBoundingRect = m_graphicsScene->itemsBoundingRect();
......@@ -479,6 +482,39 @@ void DiagramSceneModel::exportPdf(const QString &fileName)
pdfPainter.end();
addExtraSceneItems();
// TODO how to know that file was successfully created?
return true;
}
bool DiagramSceneModel::exportSvg(const QString &fileName)
{
// TODO support exporting selected elements only
removeExtraSceneItems();
QRectF sceneBoundingRect = m_graphicsScene->itemsBoundingRect();
const double border = 5;
QSvgGenerator svgGenerator;
svgGenerator.setFileName(fileName);
QSize svgSceneSize = sceneBoundingRect.size().toSize();
svgGenerator.setSize(svgSceneSize);
svgGenerator.setViewBox(QRect(QPoint(0,0), svgSceneSize));
QPainter svgPainter;
svgPainter.begin(&svgGenerator);
svgPainter.setRenderHint(QPainter::Antialiasing);
m_graphicsScene->render(&svgPainter,
QRectF(border, border,
svgPainter.device()->width() - 2 * border,
svgPainter.device()->height() - 2 * border),
sceneBoundingRect);
svgPainter.end();
addExtraSceneItems();
// TODO how to know that file was successfully created?
return true;
}
void DiagramSceneModel::selectItem(QGraphicsItem *item, bool multiSelect)
......
......@@ -113,8 +113,9 @@ public:
void selectElement(DElement *element);
void editElement(DElement *element);
void copyToClipboard();
bool exportPng(const QString &fileName);
void exportPdf(const QString &fileName);
bool exportImage(const QString &fileName);
bool exportPdf(const QString &fileName);
bool exportSvg(const QString &fileName);
void selectItem(QGraphicsItem *item, bool multiSelect);
void moveSelectedItems(QGraphicsItem *grabbedItem, const QPointF &delta);
......
......@@ -95,8 +95,8 @@ public:
std::memcpy(m_data.shortString.string, string, size);
m_data.shortString.string[size] = 0;
m_data.shortString.shortStringSize = uchar(size);
m_data.shortString.hasAllocated = false;
m_data.shortString.isReference = false;
m_data.shortString.isReadOnlyReference = false;
} else {
m_data.allocated.data.pointer = Memory::allocate(capacity + 1);
std::memcpy(m_data.allocated.data.pointer, string, size);
......@@ -104,8 +104,8 @@ public:
m_data.allocated.data.size = size;
m_data.allocated.data.capacity = capacity;
m_data.allocated.shortStringSize = 0;
m_data.allocated.hasAllocated = true;
m_data.allocated.isReference = false;
m_data.allocated.isReference = true;
m_data.allocated.isReadOnlyReference = false;
}
}
......@@ -130,7 +130,7 @@ public:
#else
SmallString(const SmallString &string)
{
if (string.isShortString() || string.isReference())
if (string.isShortString() || string.isReadOnlyReference())
m_data = string.m_data;
else
new (this) SmallString{string.data(), string.size()};
......@@ -177,16 +177,6 @@ public:
swap(first.m_data, second.m_data);
}
char &operator[](size_type index)
{
return at(index);
}
const char &operator[](size_type index) const
{
return at(index);
}
QByteArray toQByteArray() const noexcept
{
return QByteArray(data(), int(size()));
......@@ -470,17 +460,17 @@ public:
UNIT_TEST_PUBLIC:
bool isShortString() const noexcept
{
return !m_data.shortString.hasAllocated;
return !m_data.shortString.isReference;
}
bool isReference() const noexcept
bool isReadOnlyReference() const noexcept
{
return m_data.shortString.isReference;
return m_data.shortString.isReadOnlyReference;
}
bool hasAllocatedMemory() const noexcept
{
return !isShortString() && !isReference();
return !isShortString() && !isReadOnlyReference();
}
bool fitsNotInCapacity(size_type capacity) const noexcept
......
......@@ -61,9 +61,9 @@ struct AllocatedLayout {
size_type capacity;
} data;
char dummy[maximumShortStringDataAreaSize - sizeof(Data)];
std::uint8_t isReference : 1;
std::uint8_t shortStringSize: 6;
std::uint8_t hasAllocated : 1;
std::uint8_t isReadOnlyReference : 1;
std::uint8_t isReference : 1;
};
struct ReferenceLayout {
......@@ -74,15 +74,15 @@ struct ReferenceLayout {
} data;
char dummy[maximumShortStringDataAreaSize - sizeof(Data)];
std::uint8_t shortStringSize: 6;
std::uint8_t isReadOnlyReference : 1;
std::uint8_t isReference : 1;
std::uint8_t hasAllocated : 1;
};
struct ShortStringLayout {
char string[maximumShortStringDataAreaSize];
std::uint8_t shortStringSize: 6;
std::uint8_t isReadOnlyReference : 1;
std::uint8_t isReference : 1;
std::uint8_t hasAllocated : 1;
};
struct ALIGNAS_16 StringDataLayout {
......@@ -111,15 +111,15 @@ struct ALIGNAS_16 StringDataLayout {
shortString.shortStringSize = std::uint8_t(Size) - 1;
#pragma GCC diagnostic pop
#endif
shortString.hasAllocated = false;
shortString.isReference = false;
shortString.isReadOnlyReference = false;
} else {
reference.data.pointer = string;
reference.data.size = Size - 1;
reference.data.capacity = 0;
reference.shortStringSize = 0;
reference.hasAllocated = true;
reference.isReference = true;
reference.isReadOnlyReference = true;
}
#endif
}
......
......@@ -107,13 +107,13 @@ public:
constexpr
bool isShortString() const noexcept
{
return !m_data.shortString.hasAllocated;
return !m_data.shortString.isReference;
}
constexpr
bool isReference() const noexcept
bool isReadOnlyReference() const noexcept
{
return m_data.shortString.isReference;
return m_data.shortString.isReadOnlyReference;
}
operator SmallStringView() const
......
......@@ -44,21 +44,30 @@ namespace {
class ProjectFileCategorizer
{
public:
ProjectFileCategorizer(const QString &partName, const QStringList &files)
ProjectFileCategorizer(const QString &partName,
const QStringList &files,
ProjectPartBuilder::FileClassifier fileClassifier
= ProjectPartBuilder::FileClassifier())
: m_partName(partName)
{
using CppTools::ProjectFile;
QStringList cHeaders, cxxHeaders;
QVector<ProjectFile> cHeaders;
QVector<ProjectFile> cxxHeaders;
foreach (const QString &file, files) {
switch (ProjectFile::classify(file)) {
case ProjectFile::CSource: m_cSources += file; break;
case ProjectFile::CHeader: cHeaders += file; break;
case ProjectFile::CXXSource: m_cxxSources += file; break;
case ProjectFile::CXXHeader: cxxHeaders += file; break;
case ProjectFile::ObjCSource: m_objcSources += file; break;
case ProjectFile::ObjCXXSource: m_objcxxSources += file; break;
const ProjectFile::Kind kind = fileClassifier
? fileClassifier(file)
: ProjectFile::classify(file);
const ProjectFile projectFile(file, kind);
switch (kind) {
case ProjectFile::CSource: m_cSources += projectFile; break;
case ProjectFile::CHeader: cHeaders += projectFile; break;
case ProjectFile::CXXSource: m_cxxSources += projectFile; break;
case ProjectFile::CXXHeader: cxxHeaders += projectFile; break;
case ProjectFile::ObjCSource: m_objcSources += projectFile; break;
case ProjectFile::ObjCXXSource: m_objcxxSources += projectFile; break;
default:
continue;
}
......@@ -92,10 +101,10 @@ public:
bool hasObjcSources() const { return !m_objcSources.isEmpty(); }
bool hasObjcxxSources() const { return !m_objcxxSources.isEmpty(); }
QStringList cSources() const { return m_cSources; }
QStringList cxxSources() const { return m_cxxSources; }
QStringList objcSources() const { return m_objcSources; }
QStringList objcxxSources() const { return m_objcxxSources; }
QVector<ProjectFile> cSources() const { return m_cSources; }
QVector<ProjectFile> cxxSources() const { return m_cxxSources; }
QVector<ProjectFile> objcSources() const { return m_objcSources; }
QVector<ProjectFile> objcxxSources() const { return m_objcxxSources; }
bool hasMultipleParts() const { return m_partCount > 1; }
bool hasNoParts() const { return m_partCount == 0; }
......@@ -110,7 +119,10 @@ public:
private:
QString m_partName;
QStringList m_cSources, m_cxxSources, m_objcSources, m_objcxxSources;
QVector<ProjectFile> m_cSources;
QVector<ProjectFile> m_cxxSources;
QVector<ProjectFile> m_objcSources;
QVector<ProjectFile> m_objcxxSources;
int m_partCount;
};
} // anonymous namespace
......@@ -191,11 +203,12 @@ void ProjectPartBuilder::setConfigFileName(const QString &configFileName)
m_templatePart->projectConfigFile = configFileName;
}
QList<Core::Id> ProjectPartBuilder::createProjectPartsForFiles(const QStringList &files)
QList<Core::Id> ProjectPartBuilder::createProjectPartsForFiles(const QStringList &files,
FileClassifier fileClassifier)
{
QList<Core::Id> languages;
ProjectFileCategorizer cat(m_templatePart->displayName, files);
ProjectFileCategorizer cat(m_templatePart->displayName, files, fileClassifier);
if (cat.hasNoParts())
return languages;
......@@ -314,66 +327,14 @@ void ProjectPartBuilder::evaluateProjectPartToolchain(
projectPart->updateLanguageFeatures();
}
namespace Internal {
class ProjectFileAdder
{
public:
ProjectFileAdder(QVector<ProjectFile> &files);
~ProjectFileAdder();
bool maybeAdd(const QString &path);
private:
void addMapping(const char *mimeName, ProjectFile::Kind kind);
QVector<ProjectFile> &m_files;
QHash<QString, ProjectFile::Kind> m_mimeNameMapping;
};
ProjectFileAdder::ProjectFileAdder(QVector<ProjectFile> &files)
: m_files(files)
{
addMapping(CppTools::Constants::C_SOURCE_MIMETYPE, ProjectFile::CSource);
addMapping(CppTools::Constants::C_HEADER_MIMETYPE, ProjectFile::CHeader);
addMapping(CppTools::Constants::CPP_SOURCE_MIMETYPE, ProjectFile::CXXSource);
addMapping(CppTools::Constants::CPP_HEADER_MIMETYPE, ProjectFile::CXXHeader);
addMapping(CppTools::Constants::OBJECTIVE_C_SOURCE_MIMETYPE, ProjectFile::ObjCSource);
addMapping(CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE, ProjectFile::ObjCXXSource);
}
ProjectFileAdder::~ProjectFileAdder()
{
}
bool ProjectFileAdder::maybeAdd(const QString &path)
{
Utils::MimeDatabase mdb;
const Utils::MimeType mt = mdb.mimeTypeForFile(path);
if (m_mimeNameMapping.contains(mt.name())) {
m_files << ProjectFile(path, m_mimeNameMapping.value(mt.name()));
return true;
}
return false;
}
void ProjectFileAdder::addMapping(const char *mimeName, ProjectFile::Kind kind)
{
Utils::MimeDatabase mdb;
Utils::MimeType mimeType = mdb.mimeTypeForName(QLatin1String(mimeName));
if (mimeType.isValid())
m_mimeNameMapping.insert(mimeType.name(), kind);
}
}
void ProjectPartBuilder::createProjectPart(const QStringList &theSources,
void ProjectPartBuilder::createProjectPart(const QVector<ProjectFile> &theSources,
const QString &partName,
ProjectPart::LanguageVersion languageVersion,
ProjectPart::LanguageExtensions languageExtensions)
{
ProjectPart::Ptr part(m_templatePart->copy());
part->displayName = partName;
part->files = theSources;
QTC_ASSERT(part->project, return);
if (ProjectExplorer::Target *activeTarget = part->project->activeTarget()) {
......@@ -391,10 +352,6 @@ void ProjectPartBuilder::createProjectPart(const QStringList &theSources,
part->languageExtensions |= languageExtensions;
Internal::ProjectFileAdder adder(part->files);
foreach (const QString &file, theSources)
adder.maybeAdd(file);
m_pInfo.appendProjectPart(part);
}
......
......@@ -31,6 +31,8 @@
#include "projectinfo.h"
#include "projectpart.h"
#include <functional>
namespace ProjectExplorer {
class ToolChain;
}
......@@ -53,7 +55,10 @@ public:
void setDisplayName(const QString &displayName);
void setConfigFileName(const QString &configFileName);
QList<Core::Id> createProjectPartsForFiles(const QStringList &files);
using FileClassifier = std::function<ProjectFile::Kind (const QString &filePath)>;
QList<Core::Id> createProjectPartsForFiles(const QStringList &files,
FileClassifier fileClassifier = FileClassifier());
static void evaluateProjectPartToolchain(ProjectPart *projectPart,
const ProjectExplorer::ToolChain *toolChain,
......@@ -61,7 +66,8 @@ public:
const Utils::FileName &sysRoot);
private:
void createProjectPart(const QStringList &theSources, const QString &partName,
void createProjectPart(const QVector<ProjectFile> &theSources,
const QString &partName,
ProjectPart::LanguageVersion languageVersion,
ProjectPart::LanguageExtensions languageExtensions);
......
......@@ -36,6 +36,7 @@
#include <QAction>
#include <QShortcut>
#include <QMenu>
namespace ModelEditor {
namespace Internal {
......@@ -52,6 +53,7 @@ public:
QAction *deleteAction = 0;
QAction *selectAllAction = 0;
QAction *openParentDiagramAction = 0;
QAction *exportDiagramAction = 0;
};
ActionHandler::ActionHandler(const Core::Context &context, QObject *parent)
......@@ -111,6 +113,11 @@ QAction *ActionHandler::openParentDiagramAction() const
return d->openParentDiagramAction;
}
QAction *ActionHandler::exportDiagramAction() const
{
return d->exportDiagramAction;
}
void ActionHandler::createActions()
{
Core::ActionContainer *medit = Core::ActionManager::actionContainer(Core::Constants::M_EDIT);
......@@ -131,6 +138,18 @@ void ActionHandler::createActions()
medit->addAction(deleteCommand, Core::Constants::G_EDIT_COPYPASTE);
d->deleteAction = deleteCommand->action();
d->selectAllAction = registerCommand(Core::Constants::SELECTALL, [this]() { selectAll(); }, d->context)->action();
Core::ActionContainer *menuModelEditor = Core::ActionManager::createMenu(Constants::MENU_ID);
menuModelEditor->menu()->setTitle(tr("Model Editor"));
Core::ActionContainer *menuTools = Core::ActionManager::actionContainer(Core::Constants::M_TOOLS);
menuTools->addMenu(menuModelEditor);
Core::Command *exportDiagramCommand = registerCommand(
Constants::EXPORT_DIAGRAM, [this]() { exportDiagram(); }, Core::Context(), true,
tr("Export Diagram..."));
menuModelEditor->addAction(exportDiagramCommand);
d->exportDiagramAction = exportDiagramCommand->action();
d->openParentDiagramAction = registerCommand(
Constants::OPEN_PARENT_DIAGRAM, [this]() { openParentDiagram(); }, Core::Context(), true,
tr("Open Parent Diagram"), QKeySequence(QStringLiteral("Ctrl+Shift+P")))->action();
......@@ -230,6 +249,13 @@ void ActionHandler::onEditItem()
editor->editSelectedItem();
}
void ActionHandler::exportDiagram()
{
auto editor = qobject_cast<ModelEditor *>(Core::EditorManager::currentEditor());
if (editor)
editor->exportDiagram();
}
Core::Command *ActionHandler::registerCommand(const Core::Id &id, const std::function<void()> &slot,
const Core::Context &context, bool scriptable, const QString &title,
const QKeySequence &keySequence)
......
......@@ -64,6 +64,7 @@ public:
QAction *deleteAction() const;
QAction *selectAllAction() const;
QAction *openParentDiagramAction() const;
QAction *exportDiagramAction() const;
void createActions();
......@@ -79,6 +80,7 @@ private slots:
void openParentDiagram();
void onEditProperties();
void onEditItem();
void exportDiagram();
private:
Core::Command *registerCommand(const Core::Id &id, const std::function<void()> &slot,
......
......@@ -76,11 +76,14 @@
#include <QComboBox>
#include <QDir>
#include <QEvent>
#include <QFileDialog>
#include <QFileInfo>
#include <QFrame>
#include <QHBoxLayout>
#include <QImageWriter>
#include <QLabel>
#include <QMap>
#include <QMessageBox>
#include <QPainter>
#include <QPixmap>
#include <QScrollArea>
......@@ -121,6 +124,7 @@ public:
QWidget *toolbar = 0;
QComboBox *diagramSelector = 0;
SelectedArea selectedArea = SelectedArea::Nothing;
QString lastExportDirPath;
};
ModelEditor::ModelEditor(UiController *uiController, ActionHandler *actionHandler, QWidget *parent)
......@@ -514,6 +518,41 @@ void ModelEditor::editSelectedItem()
onEditSelectedElement();
}
void ModelEditor::exportDiagram()
{
qmt::MDiagram *diagram = currentDiagram();
if (diagram) {
if (d->lastExportDirPath.isEmpty())
d->lastExportDirPath = d->document->filePath().toFileInfo().canonicalPath();
QString fileName = QFileDialog::getSaveFileName(
Core::ICore::dialogParent(),
tr("Export Diagram"), d->lastExportDirPath,
tr("Images (*.png *.jpeg *.jpg *.tif *.tiff);;PDF (*.pdf);;SVG (*.svg)"));
if (!fileName.isEmpty()) {
qmt::DocumentController *documentController = d->document->documentController();
qmt::DiagramSceneModel *sceneModel = documentController->diagramsManager()->diagramSceneModel(diagram);
bool success = false;
QString suffix = QFileInfo(fileName).suffix().toLower();
// TODO use QFileDialog::selectedNameFilter() as fallback if no suffix is given
if (suffix.isEmpty()) {
suffix = QStringLiteral(".png");
fileName += suffix;
}
if (suffix == QStringLiteral(".pdf"))
success = sceneModel->exportPdf(fileName);
else if (suffix == QStringLiteral(".svg"))
success = sceneModel->exportSvg(fileName);
else
success = sceneModel->exportImage(fileName);
if (success)
d->lastExportDirPath = QFileInfo(fileName).canonicalPath();
else
QMessageBox::critical(Core::ICore::dialogParent(), tr("Exporting Diagram Failed"),
tr("Exporting the diagram into file<br>\"%1\"<br>failed.").arg(fileName));
}
}
}
qmt::MPackage *ModelEditor::guessSelectedPackage() const
{
qmt::MPackage *package = 0;
......
......@@ -86,6 +86,8 @@ public:
void openParentDiagram();
void editProperties();
void editSelectedItem();
void exportDiagram();
qmt::MPackage *guessSelectedPackage() const;
private:
......
......@@ -35,6 +35,8 @@ const char MODEL_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors",
const char REMOVE_SELECTED_ELEMENTS[] = "ModelEditor.RemoveSelectedElements";
const char DELETE_SELECTED_ELEMENTS[] = "ModelEditor.DeleteSelectedElements";
const char OPEN_PARENT_DIAGRAM[] = "ModelEditor.OpenParentDiagram";
const char MENU_ID[] = "ModelEditor.Menu";
const char EXPORT_DIAGRAM[] = "ModelEditor.ExportDiagram";
const char ACTION_ADD_PACKAGE[] = "ModelEditor.Action.AddPackage";
const char ACTION_ADD_COMPONENT[] = "ModelEditor.Action.AddComponent";
const char ACTION_ADD_CLASS[] = "ModelEditor.Action.AddClass";
......
......@@ -674,6 +674,21 @@ void QbsProject::updateDocuments(const QSet<QString> &files)
m_qbsDocuments.unite(toAdd);
}
static CppTools::ProjectFile::Kind cppFileType(const qbs::SourceArtifact &sourceFile)
{
if (sourceFile.fileTags().contains(QLatin1String("hpp")))
return CppTools::ProjectFile::CXXHeader;
if (sourceFile.fileTags().contains(QLatin1String("cpp")))
return CppTools::ProjectFile::CXXSource;
if (sourceFile.fileTags().contains(QLatin1String("c")))
return CppTools::ProjectFile::CSource;
if (sourceFile.fileTags().contains(QLatin1String("objc")))
return CppTools::ProjectFile::ObjCSource;
if (sourceFile.fileTags().contains(QLatin1String("objcpp")))
return CppTools::ProjectFile::ObjCXXSource;
return CppTools::ProjectFile::Unclassified;
}
void QbsProject::updateCppCodeModel()
{
if (!m_projectData.isValid())
......@@ -759,7 +774,11 @@ void QbsProject::updateCppCodeModel()
.arg(grp.location().line())
.arg(grp.location().column()));
QHash<QString, qbs::SourceArtifact> filePathToSourceArtifact;
foreach (const qbs::SourceArtifact &source, grp.allSourceArtifacts()) {
filePathToSourceArtifact.insert(source.filePath(), source);
foreach (const QString &tag, source.fileTags()) {
for (auto i = factoriesBegin; i != factoriesEnd; ++i) {
if ((*i)->sourceTag() != tag)
......@@ -779,8 +798,12 @@ void QbsProject::updateCppCodeModel()
}
}
const QList<Id> languages =
ppBuilder.createProjectPartsForFiles(grp.allFilePaths());
const QList<Id> languages = ppBuilder.createProjectPartsForFiles(
grp.allFilePaths(),
[filePathToSourceArtifact](const QString &filePath) {
return cppFileType(filePathToSourceArtifact.value(filePath));
});
foreach (Id language, languages)
setProjectLanguage(language, true);
}
......@@ -811,13 +834,14 @@ void QbsProject::updateCppCompilerCallData()
if (!group.isEnabled())
continue;
foreach (const QString &file, group.allFilePaths()) {
if (!CppTools::ProjectFile::isSource(CppTools::ProjectFile::classify(file)))