1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright (C) 2000 The LyX Team.
8 *======================================================
19 #pragma implementation
22 #include "insettabular.h"
25 #include "commandtags.h"
26 #include "LaTeXFeatures.h"
29 #include "insets/insettext.h"
31 const int ADD_TO_HEIGHT = 2;
32 const int ADD_TO_TABLE_WIDTH = 2;
37 InsetTabular::InsetTabular(Buffer * buf, int rows=1, int columns=1)
43 tabular = new LyXTable(rows,columns,buf);
44 the_locking_inset = 0;
46 cursor_visible = false;
48 sel_pos_start = sel_pos_end = 0;
53 InsetTabular::InsetTabular(InsetTabular const & tab, Buffer * buf)
55 tabular = new LyXTable(*(tab.tabular), buf);
56 the_locking_inset = 0;
58 cursor_visible = false;
60 sel_pos_start = sel_pos_end = 0;
65 InsetTabular::~InsetTabular()
72 InsetTabular * InsetTabular::Clone() const
74 InsetTabular * t = new InsetTabular(*this, buffer);
79 void InsetTabular::Write(ostream & os) const
81 os << "\\begin_inset Tabular\n";
82 tabular->Write(os,false);
83 os << "\\end_inset\n";
87 void InsetTabular::Read(LyXLex & lex)
92 // bool old_format = (lex.GetString() == "\\LyXTable");
93 tabular = new LyXTable(lex, buffer);
98 int InsetTabular::ascent(Painter & pain, LyXFont const & font) const
101 calculate_width_of_cells(pain, font);
104 return tabular->AscentOfRow(0);
108 int InsetTabular::descent(Painter & pain, LyXFont const & font) const
111 calculate_width_of_cells(pain, font);
114 return tabular->HeightOfTable() - tabular->AscentOfRow(0);
118 int InsetTabular::width(Painter & pain, LyXFont const & font) const
121 calculate_width_of_cells(pain, font);
124 return tabular->WidthOfTable() + (2 * ADD_TO_TABLE_WIDTH);
128 void InsetTabular::draw(Painter & pain, const LyXFont & font, int,
131 calculate_width_of_cells(pain, font);
135 const char * InsetTabular::EditMessage() const
137 return _("Opened Tabular Inset");
141 void InsetTabular::Edit(BufferView * bv, int x, int y, unsigned int button)
143 UpdatableInset::Edit(bv, x, y, button);
146 the_locking_inset = 0;
147 inset_pos = inset_x = inset_y = 0;
150 sel_pos_start = sel_pos_end = actpos;
151 sel_cell_start = sel_cell_end = actcell;
152 // bv->getOwner()->getPopups().updateFormTable();
156 void InsetTabular::InsetUnlock(BufferView * bv)
158 if (the_locking_inset)
159 the_locking_inset->InsetUnlock(bv);
161 the_locking_inset = 0;
162 if (hasCharSelection()) {
163 sel_pos_start = sel_pos_end = actpos;
164 UpdateLocal(bv, false);
166 sel_pos_start = sel_pos_end = actpos;
167 no_selection = false;
170 bool InsetTabular::LockInsetInInset(UpdatableInset *)
176 bool InsetTabular::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
179 if (!the_locking_inset)
181 if (the_locking_inset == inset) {
182 the_locking_inset->InsetUnlock(bv);
183 the_locking_inset = 0;
188 return the_locking_inset->UnlockInsetInInset(bv, inset, lr);
192 void InsetTabular::UpdateLocal(BufferView * bv, bool flag)
195 bv->updateInset(this, flag);
198 bool InsetTabular::UpdateInsetInInset(BufferView * bv, Inset * inset)
200 if (!the_locking_inset)
202 if (the_locking_inset != inset)
203 return the_locking_inset->UpdateInsetInInset(bv, inset);
208 void InsetTabular::InsetButtonRelease(BufferView *bv, int x, int y, int button)
210 if (the_locking_inset) {
211 the_locking_inset->InsetButtonRelease(bv, x-inset_x,y-inset_y,button);
214 no_selection = false;
217 void InsetTabular::InsetButtonPress(BufferView *bv, int x, int y, int)
219 if (hasCharSelection()) {
220 sel_pos_start = sel_pos_end = 0;
221 UpdateLocal(bv, false);
223 no_selection = false;
225 if (the_locking_inset) {
229 if (par->GetChar(actpos)==LYX_META_INSET)
230 inset=(UpdatableInset*)par->GetInset(actpos);
231 if (the_locking_inset == inset) {
232 the_locking_inset->InsetButtonPress(bv,x-inset_x,y-inset_y,button);
235 // otherwise unlock the_locking_inset and lock the new inset
239 the_locking_inset->InsetUnlock(bv);
240 the_locking_inset = inset;
241 the_locking_inset->Edit(bv, x - inset_x, y - inset_y, button);
245 // otherwise only unlock the_locking_inset
246 the_locking_inset->InsetUnlock(bv);
253 the_locking_inset = 0;
254 sel_pos_start = sel_pos_end = actpos;
255 sel_cell_start = sel_cell_end = actcell;
258 bview->getOwner()->getPopups().showFormTable();
259 else if (oldcell != actcell)
260 bview->getOwner()->getPopups().updateFormTable();
265 void InsetTabular::InsetMotionNotify(BufferView * bv, int x, int y, int button)
267 if (the_locking_inset) {
268 the_locking_inset->InsetMotionNotify(bv, x-inset_x,y-inset_y,button);
273 // oldcell = actcell,
277 sel_pos_end = actpos;
278 sel_cell_end = actcell;
279 if (old != sel_pos_end)
280 UpdateLocal(bv, false);
282 if (oldcell != actcell)
283 bview->getOwner()->getPopups().updateFormTable();
286 no_selection = false;
290 void InsetTabular::InsetKeyPress(XKeyEvent * xke)
292 if (the_locking_inset) {
293 the_locking_inset->InsetKeyPress(xke);
299 UpdatableInset::RESULT InsetTabular::LocalDispatch(BufferView *bv, int action,
302 no_selection = false;
303 if (UpdatableInset::LocalDispatch(bv, action, arg)) {
308 UpdatableInset::RESULT
310 if ((action < 0) && arg.empty())
313 if ((action != LFUN_DOWN) && (action != LFUN_UP) &&
314 (action != LFUN_DOWNSEL) && (action != LFUN_UPSEL))
316 if (the_locking_inset) {
317 result=the_locking_inset->LocalDispatch(bv, action, arg);
318 if (result == DISPATCHED) {
319 setWidthOfCell(actpos,actcell,actrow);
320 the_locking_inset->ToggleInsetCursor(bv);
321 UpdateLocal(bv, false);
322 the_locking_inset->ToggleInsetCursor(bv);
324 } else if (result == FINISHED) {
325 if ((action == LFUN_RIGHT) || (action == -1)) {
326 actpos = inset_pos + 1;
337 // Normal chars not handled here
340 // --- Cursor Movements ---------------------------------------------
343 sel_pos_end = actpos;
344 UpdateLocal(bv, false);
347 result= DISPATCH_RESULT(moveRight());
348 if (hasCharSelection()) {
349 sel_pos_start = sel_pos_end = actpos;
350 UpdateLocal(bv, false);
352 sel_pos_start = sel_pos_end = actpos;
356 sel_pos_end = actpos;
357 UpdateLocal(bv, false);
360 result= DISPATCH_RESULT(moveLeft());
361 if (hasCharSelection()) {
362 sel_pos_start = sel_pos_end = actpos;
363 UpdateLocal(bv, false);
365 sel_pos_start = sel_pos_end = actpos;
369 sel_pos_end = actpos;
370 UpdateLocal(bv, false);
373 result= DISPATCH_RESULT(moveDown());
374 if (hasCharSelection()) {
375 sel_pos_start = sel_pos_end = actpos;
376 UpdateLocal(bv, false);
378 sel_pos_start = sel_pos_end = actpos;
382 sel_pos_end = actpos;
383 UpdateLocal(bv, false);
386 result= DISPATCH_RESULT(moveUp());
387 if (hasCharSelection()) {
388 sel_pos_start = sel_pos_end = actpos;
389 UpdateLocal(bv, false);
391 sel_pos_start = sel_pos_end = actpos;
402 if (hasCharSelection()) {
403 sel_pos_start = sel_pos_end = actpos;
404 UpdateLocal(bv, false);
406 sel_pos_start = sel_pos_end = actpos;
410 result = UNDISPATCHED;
413 if (result!=FINISHED) {
414 if (!the_locking_inset) {
416 if (oldcell != actcell)
417 bview->getOwner()->getPopups().updateFormTable();
422 bv->unlockInset(this);
427 int InsetTabular::Latex(ostream & os, bool, bool) const
429 return tabular->Latex(os);
432 int InsetTabular::Linuxdoc(ostream &) const
437 int InsetTabular::DocBook(ostream &) const
442 void InsetTabular::Validate(LaTeXFeatures & features) const
444 if (tabular->IsLongTable())
445 features.longtable = true;
449 void InsetTabular::calculate_width_of_cells(Painter & pain, LyXFont const & font) const
458 for(i=0; i < tabular->rows; ++i) {
459 maxAsc = maxDesc = 0;
460 for(j=0; j < tabular->columns; ++j) {
461 if (tabular->IsPartOfMultiColumn(i,j))
464 inset = tabular->GetCellInset(cell);
465 maxAsc = max(maxAsc, inset->ascent(pain, font));
466 maxDesc = max(maxDesc, inset->descent(pain, font));
467 tabular->SetWidthOfCell(cell, inset->width(pain, font));
469 tabular->SetAscentOfRow(i,maxAsc+ADD_TO_HEIGHT);
470 tabular->SetDescentOfRow(i,maxDesc+ADD_TO_HEIGHT);
475 void InsetTabular::DrawCellLines(Painter & pain, int x, int baseline,
478 // Juergen, have you thought about drawing the on-off lines in a
479 // different color (gray of some kind), especially since those
480 // lines will not be there on the hardcopy anyway. (Lgb)
486 x_old -= tabular->WidthOfColumn(cell);
487 on_off = !tabular->TopLine(cell);
488 if ((!on_off || !tabular->TopAlreadyDrawed(cell)) &&
489 !tabular->IsContRow(cell))
490 pain.line(x_old, baseline - tabular->AscentOfRow(row),
491 x, baseline - tabular->AscentOfRow(row),
493 on_off ? Painter::line_onoffdash:Painter::line_solid);
494 on_off = !tabular->BottomLine(cell);
495 if ((!on_off && !tabular->RowHasContRow(cell)) ||
496 tabular->VeryLastRow(cell))
497 pain.line(x_old ,baseline + tabular->DescentOfRow(row),
498 x, baseline + tabular->DescentOfRow(row),
500 on_off ? Painter::line_onoffdash:Painter::line_solid);
501 on_off = !tabular->LeftLine(cell);
502 pain.line(x_old, baseline - tabular->AscentOfRow(row),
503 x_old, baseline + tabular->DescentOfRow(row),
505 on_off ? Painter::line_onoffdash:Painter::line_solid);
506 on_off = !tabular->RightLine(cell);
507 pain.line(x - tabular->AdditionalWidth(cell),
508 baseline - tabular->AscentOfRow(row),
509 x - tabular->AdditionalWidth(cell),
510 baseline + tabular->DescentOfRow(row),
512 on_off ? Painter::line_onoffdash:Painter::line_solid);
516 void InsetTabular::GetCursorPos(int & x, int & y)
523 void InsetTabular::ToggleInsetCursor(BufferView * bv)
525 if (the_locking_inset) {
526 the_locking_inset->ToggleInsetCursor(bv);
534 font; // = the_locking_inset->GetFont(par, actpos);
536 asc = lyxfont::maxAscent(font);
537 desc = lyxfont::maxDescent(font);
540 bv->hideLockedInsetCursor();
542 bv->showLockedInsetCursor(cx+x, cy+y, asc, desc);
543 cursor_visible = !cursor_visible;
547 void InsetTabular::ShowInsetCursor(BufferView * bv)
549 if (!cursor_visible) {
553 font; // = GetFont(par, actpos);
555 asc = lyxfont::maxAscent(font);
556 desc = lyxfont::maxDescent(font);
557 bv->fitLockedInsetCursor(cx, cy, asc, desc);
558 bv->showLockedInsetCursor(cx, cy, asc, desc);
559 cursor_visible = true;
564 void InsetTabular::HideInsetCursor(BufferView * bv)
567 ToggleInsetCursor(bv);
571 void InsetTabular::setPos(int, int, bool)
575 void InsetTabular::setWidthOfCell(int, int, int)
579 bool InsetTabular::moveRight(bool)
584 bool InsetTabular::moveLeft(bool)
589 bool InsetTabular::moveUp(bool)
594 bool InsetTabular::moveDown(bool)
599 bool InsetTabular::moveNextCell()
604 bool InsetTabular::movePrevCell()
609 void InsetTabular::resetPos()
613 bool InsetTabular::Delete()
618 void InsetTabular::SetFont(LyXFont const &)
622 void InsetTabular::TableFeatures(int, string)
630 setAlign = LYX_ALIGN_LEFT,
636 case LyXTable::ALIGN_LEFT:
637 setAlign=LYX_ALIGN_LEFT;
639 case LyXTable::ALIGN_RIGHT:
640 setAlign=LYX_ALIGN_RIGHT;
642 case LyXTable::ALIGN_CENTER:
643 setAlign=LYX_ALIGN_CENTER;
648 if (hasCellSelection()) {
649 if (sel_cell_start > sel_cell_end) {
650 selection_start = sel_cell_end;
651 selection_end = sel_cell_start;
653 selection_start = sel_cell_start;
654 selection_end = sel_cell_end;
657 selection_start = selection_end = actcell;
659 case LyXTable::SET_PWIDTH:
660 tabular->SetPWidth(actcell,val);
662 case LyXTable::SET_SPECIAL_COLUMN:
663 case LyXTable::SET_SPECIAL_MULTI:
664 tabular->SetAlignSpecial(actcell,val,feature);
666 case LyXTable::APPEND_ROW:
673 // if there is a ContRow following this row I have to add
674 // the row after the ContRow's
675 if ((pos < par->last()) && tabular->RowHasContRow(cell_org)) {
676 while((pos < par->last()) && !tabular->IsContRow(cell)) {
677 while (pos < par->last() && !par->IsNewline(pos))
679 if (pos < par->last())
683 while((pos < par->last()) && tabular->IsContRow(cell)) {
684 while (pos < par->last() && !par->IsNewline(pos))
686 if (pos < par->last())
691 if (pos < par->last())
694 while ((pos < par->last()) &&
695 ((cell == cell_org) || !tabular->IsFirstCell(cell))) {
696 while ((pos < par->last()) && !par->IsNewline(pos))
698 if (pos < par->last())
702 // insert the new cells
703 int number = tabular->NumberOfCellsInRow(cell_org);
704 for (i=0; i<number; ++i)
705 par->InsertChar(pos, LYX_META_NEWLINE);
707 // append the row into the table
708 tabular->AppendRow(cell_org);
709 calculate_width_of_cells();
713 case LyXTable::APPEND_CONT_ROW:
720 // if there is already a controw but not for this cell
721 // the AppendContRow sets only the right values but does
722 // not actually add a row
723 if (tabular->RowHasContRow(cell_org) &&
724 (tabular->CellHasContRow(cell_org) < 0)) {
725 tabular->AppendContRow(cell_org);
726 calculate_width_of_cells();
730 while ((pos < par->last()) &&
731 ((cell == cell_org) || !tabular->IsFirstCell(cell))) {
732 while (pos < par->last() && !par->IsNewline(pos))
734 if (pos < par->last())
738 // insert the new cells
739 int number = tabular->NumberOfCellsInRow(cell_org);
740 for (i=0; i<number; ++i)
741 par->InsertChar(pos, LYX_META_NEWLINE);
742 // append the row into the table
743 tabular->AppendContRow(cell_org);
744 calculate_width_of_cells();
748 case LyXTable::APPEND_COLUMN:
755 if (pos && (par->IsNewline(pos-1))) {
756 if (tabular->AppendCellAfterCell(cell_org, cell)) {
757 par->InsertChar(pos, LYX_META_NEWLINE);
765 } while (pos <= par->last());
766 // remember that the very last cell doesn't end with a newline.
767 // This saves one byte memory per table ;-)
768 if (tabular->AppendCellAfterCell(cell_org, cell))
769 par->InsertChar(par->last(), LYX_META_NEWLINE);
770 // append the column into the table
771 tabular->AppendColumn(cell_org);
772 calculate_width_of_cells();
776 case LyXTable::DELETE_ROW:
778 calculate_width_of_cells();
781 case LyXTable::DELETE_COLUMN:
786 if (!pos || (par->IsNewline(pos-1))){
787 if (tabular->DeleteCellIfColumnIsDeleted(cell, actcell)) {
789 while (pos < par->last() && !par->IsNewline(pos))
791 if (pos < par->last())
794 par->Erase(pos - 1); // the missing newline
795 // at the end of a table
796 --pos; // because of ++pos below
801 } while (pos <= par->last());
802 /* delete the column from the table */
803 tabular->DeleteColumn(actcell);
804 calculate_width_of_cells();
808 case LyXTable::TOGGLE_LINE_TOP:
809 lineSet = !tabular->TopLine(actcell);
810 for(i=selection_start; i<=selection_end; ++i)
811 tabular->SetTopLine(i,lineSet);
812 calculate_width_of_cells();
816 case LyXTable::TOGGLE_LINE_BOTTOM:
817 lineSet = !tabular->BottomLine(actcell);
818 for(i=selection_start; i<=selection_end; ++i)
819 tabular->SetBottomLine(i,lineSet);
820 calculate_width_of_cells();
824 case LyXTable::TOGGLE_LINE_LEFT:
825 lineSet = !tabular->LeftLine(actcell);
826 for(i=selection_start; i<=selection_end; ++i)
827 tabular->SetLeftLine(i,lineSet);
828 calculate_width_of_cells();
832 case LyXTable::TOGGLE_LINE_RIGHT:
833 lineSet = !tabular->RightLine(actcell);
834 for(i=selection_start; i<=selection_end; ++i)
835 tabular->SetRightLine(i,lineSet);
836 calculate_width_of_cells();
839 case LyXTable::ALIGN_LEFT:
840 case LyXTable::ALIGN_RIGHT:
841 case LyXTable::ALIGN_CENTER:
842 for(i=selection_start; i<=selection_end; ++i)
843 tabular->SetAlignment(i,setAlign);
846 case LyXTable::MULTICOLUMN:
848 if (tabular->row_of_cell(selection_start) !=
849 tabular->row_of_cell(selection_end)) {
850 WriteAlert(_("Impossible Operation!"),
851 _("Multicolumns can only be horizontally."),
855 // just multicol for one Single Cell
856 if (!hasCellSelection()) {
857 // check wether we are completly in a multicol
858 if (tabular->IsMultiColumn(actcell)) {
862 if ((newlines=tabular->UnsetMultiColumn(actcell))) {
863 while ((pos < par->last()) && !par->IsNewline(pos))
865 for (;newlines;--newlines)
866 par->InsertChar(pos, LYX_META_NEWLINE);
868 calculate_width_of_cells();
870 tabular->SetMultiColumn(actcell, 1);
875 // we have a selection so this means we just add all this
876 // cells to form a multicolumn cell
881 if (sel_pos_start > sel_pos_end) {
882 s_start = sel_pos_end;
883 s_end = sel_pos_start;
885 s_start = sel_pos_start;
888 for(i=s_start; i < s_end; ++i) {
889 if (par->IsNewline(i)) {
891 // check for double-blanks
892 if ((i && !par->IsLineSeparator(i-1)) &&
893 (i < par->last()) && !par->IsLineSeparator(i))
894 par->InsertChar(i, ' ');
900 tabular->SetMultiColumn(selection_start,number);
902 sel_cell_end = sel_cell_start;
903 calculate_width_of_cells();
907 case LyXTable::SET_ALL_LINES:
909 case LyXTable::UNSET_ALL_LINES:
910 for(i=selection_start; i<=selection_end; ++i)
911 tabular->SetAllLines(i, setLines);
912 calculate_width_of_cells();
915 case LyXTable::SET_LONGTABLE:
916 tabular->SetLongTable(true);
917 UpdateLocal(); // because this toggles displayed
919 case LyXTable::UNSET_LONGTABLE:
920 tabular->SetLongTable(false);
921 UpdateLocal(); // because this toggles displayed
923 case LyXTable::SET_ROTATE_TABLE:
924 tabular->SetRotateTable(true);
926 case LyXTable::UNSET_ROTATE_TABLE:
927 tabular->SetRotateTable(false);
929 case LyXTable::SET_ROTATE_CELL:
930 for(i=selection_start; i<=selection_end; ++i)
931 tabular->SetRotateCell(i,true);
933 case LyXTable::UNSET_ROTATE_CELL:
934 for(i=selection_start; i<=selection_end; ++i)
935 tabular->SetRotateCell(i,false);
937 case LyXTable::SET_LINEBREAKS:
938 what = !tabular->Linebreaks(tabular->FirstVirtualCell(actcell));
939 for(i=selection_start; i<=selection_end; ++i)
940 tabular->SetLinebreaks(i,what);
942 case LyXTable::SET_LTFIRSTHEAD:
943 tabular->SetLTHead(actcell,true);
945 case LyXTable::SET_LTHEAD:
946 tabular->SetLTHead(actcell,false);
948 case LyXTable::SET_LTFOOT:
949 tabular->SetLTFoot(actcell,false);
951 case LyXTable::SET_LTLASTFOOT:
952 tabular->SetLTFoot(actcell,true);
954 case LyXTable::SET_LTNEWPAGE:
955 what = !tabular->LTNewPage(actcell);
956 tabular->SetLTNewPage(actcell,what);
962 void InsetTabular::RemoveTableRow()