Skip to content

Копирование и вставка элементов на диаграммах

ramntry edited this page Jul 14, 2012 · 3 revisions

Копирование и вставка основаны на использовании QClipboard в качестве буфера, содержащего необходимые свойства копируемых элементов.

Что реализовано

  • Глубокое копирование: вместе с каждым элементом копируются и все его потомки
  • При копировании сохраняются свойства объекта
  • Сохраняются точки излома связей
  • Возможно копирование между диаграммами
  • Возможно создание только графических копий без копирования логических элементов
  • Горячие клавиши: * Копирование: Ctrl+C * Вставка полной копии элемента: Ctrl+V * Вставка только графической копии: Ctrl+Shift+V
  • Копирование и вставка посредством контекстного меню

Поведение

  • Выделенная связь копируется только в том случае, если оба элемента, которые она соединяет, тоже выделены
  • Положение нового элемента на сцене определяется в зависимости от типа вставки и от местонахождения его в контейнере:
    • Элементы вне контейнеров всегда копируются в позицию мыши
    • Элементы, копируемые вместе с содержащими их контейнерами, сохраняют своё положение внутри них
    • При полном копировании элемент, содержащийся в контейнере, но копируемый без него, вставляется в позицию курсора
    • При вставке только графических копий в этом случае поведение определяется положением курсора:
      • Если курсор находится внутри родителя исходного элемента, копия вставляется в позицию курсора в тот же контейнер
      • В ином случае - в ту же позицию, где и исходный элемент
  • Элемент без контейнера, вставляемый в позицию, где находится контейнер, способный его принять, добавляется в него.

Так, во всяком случае, должно быть =)

Нерешённые проблемы

  1. Не всегда корректно копируются элементы, способные иметь родителя, но не имеющие его. В этом случае при вставке такого элемента в то место, где находится элемент, допустимый для него в качестве контейнера, возможны следующие варианты поведения:

    • "ребёнок" добавляется в контейнер, при этом если продолжать вставку, все его последующие копии тоже будут добавляться в этот контейнер, независимо от позиции курсора на сцене;
    • "ребёнок" не добавляется в контейнер, вместо этого он вставляется на сцену, причём его позиция в таком случае непредсказуема;
    • вставка корректна, то есть элемент вставляется в нужное место и при этом не добавляется ни в какие контейнеры.

    Причины и условия воспроизведения того или иного сценария на данный момент не выяснены.

  2. При вставке графической копии вставленная связь не прикрепляется к портам, оставаясь красной.

  3. Контейнеры, содержащие какие-то элементы, при вставке имеют непредсказуемые размеры.

  4. Вставка графической копии внутрь контейнера не всегда корректна (неправильная позиция вставленной копии + изменение размеров контейнера).

Детали реализации

Копирование

При копировании нужные узлы и связи сериализуются и записываются в QClipboard. Сериализация элементов осуществляется с помощью POD-классов EdgeData и NodeData, поля которых содержат нужную для копирования информацию о связи или узле. Для каждого элемента создаётся такая структура и пишется в QByteArray, который и является содержимым буфера обмена. (Чтобы это было возможным, для структуры и для всех типов полей должны быть реализованы operator<< и operator>>, а так же типы полей (qReal::Id) должны быть зарегистрированы с помощью qRegisterMetaType() и qRegisterMetaTypeStreamOperators()).

Список копируемых узлов формируется так, чтобы каждый элемент в этом списке предшествовал всем своим потомкам. Это значительно упрощает вставку.

Содержание EdgeData и NodeData:

  • Общие поля: id и pos - id и позиция исходного элемента; logicalId - логический id, необходимый для вставки графических копий
  • EdgeData: srcId и dstId - id элементов, являющихся началом и концом связи, соответственно; portFrom и portTo - конкретные порты, к которым присоединена связь; configuration - точки излома связи
  • NodeData: parentId - id родителя копируемого узла; contents - используется для восстановления геометрии вставленного элемента и установки правильного его положения на сцене; properties - свойства узла.

Вставка

При вставке из буфера вытаскиваются (посредством QByteArray, так же, как производилось и копирование) все сохранённые в нём структуры и на основе данных, содержащихся в них, создаются новые элементы. При этом:

  • Смещение объектов определяется относительно первого в списке узла (если список пуст, то вставлять нечего, ибо связей тогда тоже нет)
  • Благодаря тому, что узлы при копировании записывались в буфер в "правильном" порядке, нам не нужно каждый раз искать по всему списку элемент, который можно вставить (с отсутствующим или уже вставленным родителем), а можно брать их последовательно, начиная с начала, потому что если у текущего элемента был родитель, то он уже вставлен
  • Используется табличка, сопоставляющая id-шники исходного элемента и копии: при вставке узла она нужна, чтобы установить правильного родителя, а при вставке связи - её начало и конец.

Clone this wiki locally