Clipboard

Title Clipboard
Author Jiří Krutil
Date 31. 5. 1999
Project KTTV
CVS $Id: clipboard.html,v 1.4 1999/06/06 10:55:21 jehne Exp $

Označená oblast textu

je souvislý úsek textu ohraničený dvěma pozicemi. Může být jak v rámci jednoho bloku (část tabulky, několik slov odstavce), tak i přes více bloků (v takovém případě může obsahovat pouze celé bloky, s výjimkou koncových, což mohou být části odstavců).

Aktuální pozice je uložena v mainblocku. Jsou tam dvě souřadnice (x, y) začátku a konce oblasti (pozice je v AU: svisle od začátku dokumentu, vodorovně od levé části bloku, v němž se okraj oblasti nachází). Dále je tam jeden flag určující, zda oblast platí (tzn. jestli je něco označeno).

Jelikož text lze označovat i v textových rámečcích slidů a obsah těchto rámečků není z mainblocku dostupný, lze se k příslušnému textu dostat právě přes pozici "na obrazovce", která odstavec jednoznačně identifikuje (pokud si uvědomíte, že ačkoli může být více textových rámečků přes sebe, pouze jeden z nich má ohnisko). V případě, že je třeba s oblastí v textovém rámečku něco provést (například ji zkopírovat do clipboardu), je příslušná událost prostřednictvím slidu předána blocklistu odpovídajícímu vybranému textovému rámečku. Tento postup lze samozřejmě použít i rekurzivně (obsahuje-li například textový rámeček zase slide).

V tomto dokumentu není uvedeno, jak lze textovou oblast označit. Počítá se s tím, že již označena je.

Clipboard

se skládá ze tří schránek. Jedna slouží pro práci se slidem (lze do ní ukládat elementy slidu jako skupinu), druhá pro práci s textem a celými bloky a třetí pro práci s tabulkami (lze do ní uložit část tabulky). Chce-li uživatel uložit do schránky tabulku či slide jako celek, musí ji/jej označit jako blok a uložit do schránky pro bloky. Uvedené tři schránky jsou nezávislé a lze je používat najednou. Clipboard má v rámci KTTV právě jednu instanci, takže pomocí schránek lze přenášet data mezi dokumenty.

Objekt kClipboard je celkově celkem pasivní. Vlastně nedělá nic jiného, než že si něco pamatuje a na požádání to sdělí nebo změní. Konkrétnější informace lze najít v headeru clipboard.h.

Clipboard pro slide si pouze pamatuje ukazatel na skupinu obsahující objekty nacházející se v clipboardu. Tato skupina slouží pouze ke sdružení elementů, které mají být do clipboardu uloženy. Použití tohoto clipboardu je jednoduché a lze je také vyčíst z headeru.

Clipboard pro tabulku může obsahovat část tabulky, která je "zabalena" do samostatné tabulky, na níž obsahuje tento clipboard ukazatel. Použití je obdobné jako u schránky pro slide. Tuto schránku lze použít pouze pro část jedné tabulky. Pokud uživatel v rámci označování oblasti označí i něco mimo tabulku, automaticky se do selekce přidá i zbytek tabulky, takže se rázem jedná o sekvenci bloků a patří to do schránky pro bloky.

Clipboard pro bloky může obsahovat jeden blok a má dva flagy určující, otevřenost/uzavřenost textu v clipboardu. Tyto flagy jsou využívány pouze někdy (například pro určení uzavřenosti odstavce při jeho kopírování do clipboardu). Blokem uloženým v clipboardu může být tabulka, slide nebo blocklist. Jedná-li se o tabulku nebo slide, jde o celý tento objekt (chápaný jako blok), který lze jako celek vložit kamkoli do odstavce, který se tím rozdělí.

Důležitá poznámka 1:
Spolu s Králíkem jsme došli k závěru, že není důvod k tomu, aby nebylo možné vkládat slidy i do vnořených blocklistů. Podle našeho názoru se tím nic nekomplikuje, právě naopak se tak struktura dokumentu zobecnuje a zjednodušuje se tak implementace i funkčnost některých operací. Je-li například v clipboardu uloženo několik odstavců a mezi nimi i slide, muselo by se při vkládání tohoto blocklistu dovnitř nějakého zanořeného seznamu speciálně ošetřovat umístění slidu na základní hladinu (na rozdíl od ostatních odstavců). PS: Kendy s tím taky souhlasil.

Důležitá poznámka 2:
Bránili jsme se sice statečně, ale je to tady: každý blok bude muset vědět, co je. Lépe řečeno, obecný blok obsahuje informaci o svém typu, kterou si nastaví jednotliví potomci po svém. Tedy proměnná blocktype třídy kBlock bude vždy obsahovat jednu z hodnot: PARAGRAPH, SLIDE, TABLE, BLOCKLIST. Je to potřeba pro vkládání z clipboardu (viz zde).

Distribuce událostí

Vyvolá-li uživatel některou událost clipboardu, spustí se v hlavním programu odpovídající funkce (např DoCopy). Ta zjistí, který clipboard se má použít a zavolá příslušnou metodu příslušného bloku. Jedná-li se o označení v rámci slidu/tabulky, zavolá se např. metoda kSlide::CopySelection, která vrátí skupinu/tabulku obsahující kopii označených objektů.

Pokud se však jedná o odstavec (tzn. kus odstavce či několik bloků), zavolá se například metoda OnCopy, která je definovaná jako abstraktní už ve třídě kBlock a každá z ní odvozená třída ji předefinovává. Takovéto volání si distribuuje podobně jako událost od mainblocku až na nejnižší úroven. Parametry a návratové hodnoty metod OnCopy a OnPaste jsou popsány dále.

Clipboard pro bloky

je neuvěřitelně vymakaná věc, za což vděčíte Králíkovi a Jehněmu. Trošku si sice uprudnul i Jindřich, ale na to nic nedejte.

Clipboard obecně nabízí operace Copy, Cut a Paste. Zde jsou popsány operace Copy, Paste a Delete. Poslední uvedená se samozřejmě netýká clipboardu, ale překvapivě s nimi souvisí. Například tak, že Cut lze udělat pomocí Copy+Delete. Je to sice trochu divné, nebot se kopíruje něco, co nemusí, ale je to jednoduché!

Operace Copy

Po zmáčknutí klávesy/ikony/menu odpovídající akci Copy se děje toto:
  1. V main.cc se zavolá funkce DoCopy.

  2. Funkce DoCopy nejprve zkontroluje, zde je označena nějaká oblast a zjistí, jaký clipboard se má použít. Je-li fokus v tabulce či ve slidu, zavolá se metoda CopySelection třídy kTable, ev. kSlide, která provede jednoduché zkopírování do svého clipboardu.
    Pokud je však fokus v odstavci (který se může nacházet i uvnitř textového rámečku ve slidu nebo políčka tabulky), zavolá se metoda mainblock->OnCopy. Tato událost se prostřednictvím blocklistů distribuuje dovnitř struktury.
    V závislosti na tom, jakému typu bloku událost přijde, se provede jedna z možností:

  3. Návratovou hodnotou metody OnCopy je ukazatel na blok, který se má do clipboardu vložit, a také dva flagy určující otevřenost/uzavřenost. Tento blok se vloží do clipboardu. U příznaků otevřenosti se ještě musí zkontrolovat, zda krajní bloky, které jsou otevřené (to by znamenalo, že to jsou odstavce), nejsou vnořeny. Přesněji řečeno v případě, že se do clipboardu ukládá blocklist, se musí ověřit, zda otevřené krajní bloky tohoto blocklistu jsou odstavce. Pokud ne (to by musely být blocklisty), se jim příznak nastaví na uzavřené.
Z hlediska UNDO se operace Copy nijak nezaznamenává.

Operace Delete

Po zmáčknutí klávesy/ikony/menu odpovídající akci Delete se děje toto:
  1. Pokud je označena nějaká oblast, jedná se o tuto operaci delete. (Pokud ne, předá se prostě událost příslušnému odstavci.) V main.cc se zavolá funkce DoDelete.

  2. Funkce DoDelete zavolá událost OnDelete objektu mainblock.

  3. Tato událost se šíří stejně jako událost OnCopy, dokonce jsou stejné i návratové hodnoty: text a příznaky uzavřenosti. Zároven se však z blocklistů odpojují příslušné bloky (dá se říci, že se přemistují do blocklistu, který se vrací). Pokud blocklist tuto událost distribuuje bloku, který není v oblasti celý, nevypouští jej z blocklistu, protože v takovém bloku zůstává text, který je mimo oblast, ale do vznikajícího blocklistu připojí pouze to, co tento blok vrátil. Poté, co blocklist získá smazanou část nějakého odstavce nebo slidu, zavolá na tento blok metodu DeleteTargets, čímž zajistí, že cíle linků obsažené ve smazaném textu budou odstraněny z globálního seznamu cílů.

  4. Návratovou hodnotou metody OnDelete je smazaný text, který se uloží na UNDO zásobník spolu s informací o mazání.

Operace Cut

Zde je to opravdu jednoduché. Opět máme funkci DoCut, která ovšem udělá pouze toto:
  1. Nejprve zkontroluje, zda je co vystřihnout, tedy je-li něco označeno.

  2. Zavolá funkci DoCopy (čímž se text zkopíruje do clipboardu).

  3. Zavolá funkci DoDelete. Text se smaže z dokumentu a přemístí se do UNDO zásobníku. Tato operace tam sice bude zaznamenána jako "mazání", ale to je jedno, protože stav clipboardu do UNDO stejně nezahrnujeme, jde pouze o efekt z hlediska textu dokumentu.

Interface třídy kParagraph pro funkci Paste

Pro účely vkládání z clipboardu nabízí třída kParagraph tyto metody:

Operace Paste

Po zmáčknutí klávesy/ikony/menu odpovídající akci Delete se děje toto:
  1. V main.cc se zavolá funkce DoPaste.

  2. Funkce DoPaste zkontroluje, zda je označena nějaká oblast. Pokud ano, nejprve zavolá na mainblock událost OnDelete, čímž se smaže označená oblast. Vrácený ukazatel si zapamatuje, protože smazaný text bude ukládat do UNDO.
    Poté (i když nebylo nic označeno) zjistí aktuální odstavec a přes něj jeho nejbližší nadřízený blocklist. Pak na tento blocklist zavolá metodu OnPaste(clipboard_contents, actual_block).

    V rámci tohoto blocklistu se chování liší podle typu bloku, který vkládáme z clipboardu.

  3. Metoda OnPaste nic nevrací, ale ještě musí funkce DoPaste uložit do UNDO zásobníku informaci o tom, co se stalo. Uloží tam záznam o operaci Paste a dosadí ukazatele na smazaný text (pokud je) a rozsah pozic vloženého textu.