ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

table.c
Go to the documentation of this file.
00001 /*
00002  * RichEdit functions dealing with on tables
00003  *
00004  * Copyright 2008 by Dylan Smith
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  */
00020 
00021 /*
00022  * The implementation of tables differs greatly between version 3.0
00023  * (in riched20.dll) and version 4.1 (in msftedit.dll) of richedit controls.
00024  * Currently Wine is not distinguishing between version 3.0 and version 4.1,
00025  * so v4.1 is assumed unless v1.0 is being emulated (i.e. riched32.dll is used).
00026  * If this lack of distinction causes a bug in a Windows application, then Wine
00027  * will need to start making this distinction.
00028  *
00029  * Richedit version 1.0 - 3.0:
00030  *   Tables are implemented in these versions using tabs at the end of cells,
00031  *   and tab stops to position the cells.  The paragraph format flag PFE_TABLE
00032  *   will indicate that the paragraph is a table row.  Note that in this
00033  *   implementation there is one paragraph per table row.
00034  *
00035  * Richedit version 4.1:
00036  *   Tables are implemented such that cells can contain multiple paragraphs,
00037  *   each with it's own paragraph format, and cells may even contain tables
00038  *   nested within the cell.
00039  *
00040  *   There is also a paragraph at the start of each table row that contains
00041  *   the rows paragraph format (e.g. to change the row alignment to row), and a
00042  *   paragraph at the end of the table row with the PFE_TABLEROWDELIMITER flag
00043  *   set. The paragraphs at the start and end of the table row should always be
00044  *   empty, but should have a length of 2.
00045  *
00046  *   Wine implements this using display items (ME_DisplayItem) with a type of
00047  *   diCell.  These cell display items store the cell properties, and are
00048  *   inserted into the editors linked list before each cell, and at the end of
00049  *   the last cell. The cell display item for a cell comes before the paragraphs
00050  *   for the cell, but the last cell display item refers to no cell, so it is
00051  *   just a delimiter.
00052  */
00053 
00054 #include "editor.h"
00055 #include "rtf.h"
00056 
00057 WINE_DEFAULT_DEBUG_CHANNEL(richedit_lists);
00058 
00059 static ME_DisplayItem* ME_InsertEndParaFromCursor(ME_TextEditor *editor,
00060                                                   int nCursor,
00061                                                   ME_String *eol_str,
00062                                                   int paraFlags)
00063 {
00064   ME_Style *pStyle = ME_GetInsertStyle(editor, nCursor);
00065   ME_DisplayItem *tp;
00066   ME_Cursor* cursor = &editor->pCursors[nCursor];
00067   if (cursor->nOffset)
00068     ME_SplitRunSimple(editor, cursor);
00069 
00070   tp = ME_SplitParagraph(editor, cursor->pRun, pStyle, eol_str, paraFlags);
00071   ME_ReleaseStyle(pStyle);
00072   cursor->pPara = tp;
00073   cursor->pRun = ME_FindItemFwd(tp, diRun);
00074   return tp;
00075 }
00076 
00077 ME_DisplayItem* ME_InsertTableRowStartFromCursor(ME_TextEditor *editor)
00078 {
00079   ME_DisplayItem *para;
00080   WCHAR cr_lf[] = {'\r', '\n', 0};
00081   ME_String *eol_str = ME_MakeStringN(cr_lf, 2);
00082   para = ME_InsertEndParaFromCursor(editor, 0, eol_str, MEPF_ROWSTART);
00083   return para->member.para.prev_para;
00084 }
00085 
00086 ME_DisplayItem* ME_InsertTableRowStartAtParagraph(ME_TextEditor *editor,
00087                                                   ME_DisplayItem *para)
00088 {
00089   ME_DisplayItem *prev_para, *end_para;
00090   ME_Cursor savedCursor = editor->pCursors[0];
00091   ME_DisplayItem *startRowPara;
00092   editor->pCursors[0].pPara = para;
00093   editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
00094   editor->pCursors[0].nOffset = 0;
00095   editor->pCursors[1] = editor->pCursors[0];
00096   startRowPara = ME_InsertTableRowStartFromCursor(editor);
00097   savedCursor.pPara = ME_GetParagraph(savedCursor.pRun);
00098   editor->pCursors[0] = savedCursor;
00099   editor->pCursors[1] = editor->pCursors[0];
00100 
00101   end_para = editor->pCursors[0].pPara->member.para.next_para;
00102   prev_para = startRowPara->member.para.next_para;
00103   para = prev_para->member.para.next_para;
00104   while (para != end_para)
00105   {
00106     para->member.para.pCell = prev_para->member.para.pCell;
00107     para->member.para.nFlags |= MEPF_CELL;
00108     para->member.para.nFlags &= ~(MEPF_ROWSTART|MEPF_ROWEND);
00109     para->member.para.pFmt->dwMask |= PFM_TABLE|PFM_TABLEROWDELIMITER;
00110     para->member.para.pFmt->wEffects |= PFE_TABLE;
00111     para->member.para.pFmt->wEffects &= ~PFE_TABLEROWDELIMITER;
00112     prev_para = para;
00113     para = para->member.para.next_para;
00114   }
00115   return startRowPara;
00116 }
00117 
00118 /* Inserts a diCell and starts a new paragraph for the next cell.
00119  *
00120  * Returns the first paragraph of the new cell. */
00121 ME_DisplayItem* ME_InsertTableCellFromCursor(ME_TextEditor *editor)
00122 {
00123   ME_DisplayItem *para;
00124   WCHAR tab = '\t';
00125   ME_String *eol_str = ME_MakeStringN(&tab, 1);
00126   para = ME_InsertEndParaFromCursor(editor, 0, eol_str, MEPF_CELL);
00127   return para;
00128 }
00129 
00130 ME_DisplayItem* ME_InsertTableRowEndFromCursor(ME_TextEditor *editor)
00131 {
00132   ME_DisplayItem *para;
00133   WCHAR cr_lf[] = {'\r', '\n', 0};
00134   ME_String *eol_str = ME_MakeStringN(cr_lf, 2);
00135   para = ME_InsertEndParaFromCursor(editor, 0, eol_str, MEPF_ROWEND);
00136   return para->member.para.prev_para;
00137 }
00138 
00139 ME_DisplayItem* ME_GetTableRowEnd(ME_DisplayItem *para)
00140 {
00141   ME_DisplayItem *cell;
00142   assert(para);
00143   if (para->member.para.nFlags & MEPF_ROWEND)
00144     return para;
00145   if (para->member.para.nFlags & MEPF_ROWSTART)
00146     para = para->member.para.next_para;
00147   cell = para->member.para.pCell;
00148   assert(cell && cell->type == diCell);
00149   while (cell->member.cell.next_cell)
00150     cell = cell->member.cell.next_cell;
00151 
00152   para = ME_FindItemFwd(cell, diParagraph);
00153   assert(para && para->member.para.nFlags & MEPF_ROWEND);
00154   return para;
00155 }
00156 
00157 ME_DisplayItem* ME_GetTableRowStart(ME_DisplayItem *para)
00158 {
00159   ME_DisplayItem *cell;
00160   assert(para);
00161   if (para->member.para.nFlags & MEPF_ROWSTART)
00162     return para;
00163   if (para->member.para.nFlags & MEPF_ROWEND)
00164     para = para->member.para.prev_para;
00165   cell = para->member.para.pCell;
00166   assert(cell && cell->type == diCell);
00167   while (cell->member.cell.prev_cell)
00168     cell = cell->member.cell.prev_cell;
00169 
00170   para = ME_FindItemBack(cell, diParagraph);
00171   assert(para && para->member.para.nFlags & MEPF_ROWSTART);
00172   return para;
00173 }
00174 
00175 /* Make a bunch of assertions to make sure tables haven't been corrupted.
00176  *
00177  * These invariants may not hold true in the middle of streaming in rich text
00178  * or during an undo and redo of streaming in rich text. It should be safe to
00179  * call this method after an event is processed.
00180  */
00181 void ME_CheckTablesForCorruption(ME_TextEditor *editor)
00182 {
00183   if(TRACE_ON(richedit_lists))
00184   {
00185     TRACE("---\n");
00186     ME_DumpDocument(editor->pBuffer);
00187   }
00188 #ifndef NDEBUG
00189   {
00190     ME_DisplayItem *p, *pPrev;
00191     pPrev = editor->pBuffer->pFirst;
00192     p = pPrev->next;
00193     if (!editor->bEmulateVersion10) /* v4.1 */
00194     {
00195       while (p->type == diParagraph)
00196       {
00197         assert(p->member.para.pFmt->dwMask & PFM_TABLE);
00198         assert(p->member.para.pFmt->dwMask & PFM_TABLEROWDELIMITER);
00199         if (p->member.para.pCell)
00200         {
00201           assert(p->member.para.nFlags & MEPF_CELL);
00202           assert(p->member.para.pFmt->wEffects & PFE_TABLE);
00203         }
00204         if (p->member.para.pCell != pPrev->member.para.pCell)
00205         {
00206           /* There must be a diCell in between the paragraphs if pCell changes. */
00207           ME_DisplayItem *pCell = ME_FindItemBack(p, diCell);
00208           assert(pCell);
00209           assert(ME_FindItemBack(p, diRun) == ME_FindItemBack(pCell, diRun));
00210         }
00211         if (p->member.para.nFlags & MEPF_ROWEND)
00212         {
00213           /* ROWEND must come after a cell. */
00214           assert(pPrev->member.para.pCell);
00215           assert(p->member.para.pCell
00216                  == pPrev->member.para.pCell->member.cell.parent_cell);
00217           assert(p->member.para.pFmt->wEffects & PFE_TABLEROWDELIMITER);
00218         }
00219         else if (p->member.para.pCell)
00220         {
00221           assert(!(p->member.para.pFmt->wEffects & PFE_TABLEROWDELIMITER));
00222           assert(pPrev->member.para.pCell ||
00223                  pPrev->member.para.nFlags & MEPF_ROWSTART);
00224           if (pPrev->member.para.pCell &&
00225               !(pPrev->member.para.nFlags & MEPF_ROWSTART))
00226           {
00227             assert(p->member.para.pCell->member.cell.parent_cell
00228                    == pPrev->member.para.pCell->member.cell.parent_cell);
00229             if (pPrev->member.para.pCell != p->member.para.pCell)
00230               assert(pPrev->member.para.pCell
00231                      == p->member.para.pCell->member.cell.prev_cell);
00232           }
00233         }
00234         else if (!(p->member.para.nFlags & MEPF_ROWSTART))
00235         {
00236           assert(!(p->member.para.pFmt->wEffects & PFE_TABLEROWDELIMITER));
00237           /* ROWSTART must be followed by a cell. */
00238           assert(!(p->member.para.nFlags & MEPF_CELL));
00239           /* ROWSTART must be followed by a cell. */
00240           assert(!(pPrev->member.para.nFlags & MEPF_ROWSTART));
00241         }
00242         pPrev = p;
00243         p = p->member.para.next_para;
00244       }
00245     } else { /* v1.0 - 3.0 */
00246       while (p->type == diParagraph)
00247       {
00248         assert(!(p->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND|MEPF_CELL)));
00249         assert(p->member.para.pFmt->dwMask & PFM_TABLE);
00250         assert(!(p->member.para.pFmt->wEffects & PFE_TABLEROWDELIMITER));
00251         assert(!p->member.para.pCell);
00252         p = p->member.para.next_para;
00253       }
00254       return;
00255     }
00256     assert(p->type == diTextEnd);
00257     assert(!pPrev->member.para.pCell);
00258   }
00259 #endif
00260 }
00261 
00262 BOOL ME_IsInTable(ME_DisplayItem *pItem)
00263 {
00264   PARAFORMAT2 *pFmt;
00265   if (!pItem)
00266     return FALSE;
00267   if (pItem->type == diRun)
00268     pItem = ME_GetParagraph(pItem);
00269   if (pItem->type != diParagraph)
00270     return FALSE;
00271   pFmt = pItem->member.para.pFmt;
00272   return pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE;
00273 }
00274 
00275 /* Table rows should either be deleted completely or not at all. */
00276 void ME_ProtectPartialTableDeletion(ME_TextEditor *editor, ME_Cursor *c, int *nChars)
00277 {
00278   int nOfs = ME_GetCursorOfs(c);
00279   ME_Cursor c2 = *c;
00280   ME_DisplayItem *this_para = c->pPara;
00281   ME_DisplayItem *end_para;
00282 
00283   ME_MoveCursorChars(editor, &c2, *nChars);
00284   end_para = c2.pPara;
00285   if (c2.pRun->member.run.nFlags & MERF_ENDPARA) {
00286     /* End offset might be in the middle of the end paragraph run.
00287      * If this is the case, then we need to use the next paragraph as the last
00288      * paragraphs.
00289      */
00290     int remaining = nOfs + *nChars - c2.pRun->member.run.nCharOfs
00291                     - end_para->member.para.nCharOfs;
00292     if (remaining)
00293     {
00294       assert(remaining < c2.pRun->member.run.strText->nLen);
00295       end_para = end_para->member.para.next_para;
00296     }
00297   }
00298   if (!editor->bEmulateVersion10) { /* v4.1 */
00299     if (this_para->member.para.pCell != end_para->member.para.pCell ||
00300         ((this_para->member.para.nFlags|end_para->member.para.nFlags)
00301          & (MEPF_ROWSTART|MEPF_ROWEND)))
00302     {
00303       while (this_para != end_para)
00304       {
00305         ME_DisplayItem *next_para = this_para->member.para.next_para;
00306         BOOL bTruancateDeletion = FALSE;
00307         if (this_para->member.para.nFlags & MEPF_ROWSTART) {
00308           /* The following while loop assumes that next_para is MEPF_ROWSTART,
00309            * so moving back one paragraph let's it be processed as the start
00310            * of the row. */
00311           next_para = this_para;
00312           this_para = this_para->member.para.prev_para;
00313         } else if (next_para->member.para.pCell != this_para->member.para.pCell
00314                    || this_para->member.para.nFlags & MEPF_ROWEND)
00315         {
00316           /* Start of the deletion from after the start of the table row. */
00317           bTruancateDeletion = TRUE;
00318         }
00319         while (!bTruancateDeletion &&
00320                next_para->member.para.nFlags & MEPF_ROWSTART)
00321         {
00322           next_para = ME_GetTableRowEnd(next_para)->member.para.next_para;
00323           if (next_para->member.para.nCharOfs > nOfs + *nChars)
00324           {
00325             /* End of deletion is not past the end of the table row. */
00326             next_para = this_para->member.para.next_para;
00327             /* Delete the end paragraph preceding the table row if the
00328              * preceding table row will be empty. */
00329             if (this_para->member.para.nCharOfs >= nOfs)
00330             {
00331               next_para = next_para->member.para.next_para;
00332             }
00333             bTruancateDeletion = TRUE;
00334           } else {
00335             this_para = next_para->member.para.prev_para;
00336           }
00337         }
00338         if (bTruancateDeletion)
00339         {
00340           ME_Run *end_run = &ME_FindItemBack(next_para, diRun)->member.run;
00341           int nCharsNew = (next_para->member.para.nCharOfs - nOfs
00342                            - end_run->strText->nLen);
00343           nCharsNew = max(nCharsNew, 0);
00344           assert(nCharsNew <= *nChars);
00345           *nChars = nCharsNew;
00346           break;
00347         }
00348         this_para = next_para;
00349       }
00350     }
00351   } else { /* v1.0 - 3.0 */
00352     ME_DisplayItem *pRun;
00353     int nCharsToBoundary;
00354 
00355     if ((this_para->member.para.nCharOfs != nOfs || this_para == end_para) &&
00356         this_para->member.para.pFmt->dwMask & PFM_TABLE &&
00357         this_para->member.para.pFmt->wEffects & PFE_TABLE)
00358     {
00359       pRun = c->pRun;
00360       /* Find the next tab or end paragraph to use as a delete boundary */
00361       while (!(pRun->member.run.nFlags & (MERF_TAB|MERF_ENDPARA)))
00362         pRun = ME_FindItemFwd(pRun, diRun);
00363       nCharsToBoundary = pRun->member.run.nCharOfs
00364                          - c->pRun->member.run.nCharOfs
00365                          - c->nOffset;
00366       *nChars = min(*nChars, nCharsToBoundary);
00367     } else if (end_para->member.para.pFmt->dwMask & PFM_TABLE &&
00368                end_para->member.para.pFmt->wEffects & PFE_TABLE)
00369     {
00370       /* The deletion starts from before the row, so don't join it with
00371        * previous non-empty paragraphs. */
00372       ME_DisplayItem *curPara;
00373       pRun = NULL;
00374       if (nOfs > this_para->member.para.nCharOfs) {
00375         pRun = ME_FindItemBack(end_para, diRun);
00376         curPara = end_para->member.para.prev_para;
00377       }
00378       if (!pRun) {
00379         pRun = ME_FindItemFwd(end_para, diRun);
00380         curPara = end_para;
00381       }
00382       if (pRun)
00383       {
00384         nCharsToBoundary = curPara->member.para.nCharOfs
00385                            + pRun->member.run.nCharOfs
00386                            - nOfs;
00387         if (nCharsToBoundary >= 0)
00388           *nChars = min(*nChars, nCharsToBoundary);
00389       }
00390     }
00391     if (*nChars < 0)
00392       nChars = 0;
00393   }
00394 }
00395 
00396 ME_DisplayItem* ME_AppendTableRow(ME_TextEditor *editor,
00397                                   ME_DisplayItem *table_row)
00398 {
00399   WCHAR endl = '\r', tab = '\t';
00400   ME_DisplayItem *run;
00401   PARAFORMAT2 *pFmt;
00402   int i;
00403 
00404   assert(table_row);
00405   assert(table_row->type == diParagraph);
00406   if (!editor->bEmulateVersion10) { /* v4.1 */
00407     ME_DisplayItem *insertedCell, *para, *cell, *prevTableEnd;
00408     cell = ME_FindItemFwd(ME_GetTableRowStart(table_row), diCell);
00409     prevTableEnd = ME_GetTableRowEnd(table_row);
00410     para = prevTableEnd->member.para.next_para;
00411     run = ME_FindItemFwd(para, diRun);
00412     editor->pCursors[0].pPara = para;
00413     editor->pCursors[0].pRun = run;
00414     editor->pCursors[0].nOffset = 0;
00415     editor->pCursors[1] = editor->pCursors[0];
00416     para = ME_InsertTableRowStartFromCursor(editor);
00417     insertedCell = ME_FindItemFwd(para, diCell);
00418     /* Copy cell properties */
00419     insertedCell->member.cell.nRightBoundary = cell->member.cell.nRightBoundary;
00420     insertedCell->member.cell.border = cell->member.cell.border;
00421     while (cell->member.cell.next_cell) {
00422       cell = cell->member.cell.next_cell;
00423       para = ME_InsertTableCellFromCursor(editor);
00424       insertedCell = ME_FindItemBack(para, diCell);
00425       /* Copy cell properties */
00426       insertedCell->member.cell.nRightBoundary = cell->member.cell.nRightBoundary;
00427       insertedCell->member.cell.border = cell->member.cell.border;
00428     };
00429     para = ME_InsertTableRowEndFromCursor(editor);
00430     *para->member.para.pFmt = *prevTableEnd->member.para.pFmt;
00431     /* return the table row start for the inserted paragraph */
00432     return ME_FindItemFwd(cell, diParagraph)->member.para.next_para;
00433   } else { /* v1.0 - 3.0 */
00434     run = ME_FindItemBack(table_row->member.para.next_para, diRun);
00435     pFmt = table_row->member.para.pFmt;
00436     assert(pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE);
00437     editor->pCursors[0].pPara = table_row;
00438     editor->pCursors[0].pRun = run;
00439     editor->pCursors[0].nOffset = 0;
00440     editor->pCursors[1] = editor->pCursors[0];
00441     ME_InsertTextFromCursor(editor, 0, &endl, 1, run->member.run.style);
00442     run = editor->pCursors[0].pRun;
00443     for (i = 0; i < pFmt->cTabCount; i++) {
00444       ME_InsertTextFromCursor(editor, 0, &tab, 1, run->member.run.style);
00445     }
00446     return table_row->member.para.next_para;
00447   }
00448 }
00449 
00450 /* Selects the next table cell or appends a new table row if at end of table */
00451 static void ME_SelectOrInsertNextCell(ME_TextEditor *editor,
00452                                       ME_DisplayItem *run)
00453 {
00454   ME_DisplayItem *para = ME_GetParagraph(run);
00455   int i;
00456 
00457   assert(run && run->type == diRun);
00458   assert(ME_IsInTable(run));
00459   if (!editor->bEmulateVersion10) { /* v4.1 */
00460     ME_DisplayItem *cell;
00461     /* Get the initial cell */
00462     if (para->member.para.nFlags & MEPF_ROWSTART) {
00463       cell = para->member.para.next_para->member.para.pCell;
00464     } else if (para->member.para.nFlags & MEPF_ROWEND) {
00465       cell = para->member.para.prev_para->member.para.pCell;
00466     } else {
00467       cell = para->member.para.pCell;
00468     }
00469     assert(cell);
00470     /* Get the next cell. */
00471     if (cell->member.cell.next_cell &&
00472         cell->member.cell.next_cell->member.cell.next_cell)
00473     {
00474       cell = cell->member.cell.next_cell;
00475     } else {
00476       para = ME_GetTableRowEnd(ME_FindItemFwd(cell, diParagraph));
00477       para = para->member.para.next_para;
00478       assert(para);
00479       if (para->member.para.nFlags & MEPF_ROWSTART) {
00480         cell = para->member.para.next_para->member.para.pCell;
00481       } else {
00482         /* Insert row */
00483         para = para->member.para.prev_para;
00484         para = ME_AppendTableRow(editor, ME_GetTableRowStart(para));
00485         /* Put cursor at the start of the new table row */
00486         para = para->member.para.next_para;
00487         editor->pCursors[0].pPara = para;
00488         editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
00489         editor->pCursors[0].nOffset = 0;
00490         editor->pCursors[1] = editor->pCursors[0];
00491         ME_WrapMarkedParagraphs(editor);
00492         return;
00493       }
00494     }
00495     /* Select cell */
00496     editor->pCursors[1].pRun = ME_FindItemFwd(cell, diRun);
00497     editor->pCursors[1].pPara = ME_GetParagraph(editor->pCursors[1].pRun);
00498     editor->pCursors[1].nOffset = 0;
00499     assert(editor->pCursors[0].pRun);
00500     cell = cell->member.cell.next_cell;
00501     editor->pCursors[0].pRun = ME_FindItemBack(cell, diRun);
00502     editor->pCursors[0].pPara = ME_GetParagraph(editor->pCursors[0].pRun);
00503     editor->pCursors[0].nOffset = 0;
00504     assert(editor->pCursors[1].pRun);
00505   } else { /* v1.0 - 3.0 */
00506     if (run->member.run.nFlags & MERF_ENDPARA &&
00507         ME_IsInTable(ME_FindItemFwd(run, diParagraphOrEnd)))
00508     {
00509       run = ME_FindItemFwd(run, diRun);
00510       assert(run);
00511     }
00512     for (i = 0; i < 2; i++)
00513     {
00514       while (!(run->member.run.nFlags & MERF_TAB))
00515       {
00516         run = ME_FindItemFwd(run, diRunOrParagraphOrEnd);
00517         if (run->type != diRun)
00518         {
00519           para = run;
00520           if (ME_IsInTable(para))
00521           {
00522             run = ME_FindItemFwd(para, diRun);
00523             assert(run);
00524             editor->pCursors[0].pPara = para;
00525             editor->pCursors[0].pRun = run;
00526             editor->pCursors[0].nOffset = 0;
00527             i = 1;
00528           } else {
00529             /* Insert table row */
00530             para = ME_AppendTableRow(editor, para->member.para.prev_para);
00531             /* Put cursor at the start of the new table row */
00532             editor->pCursors[0].pPara = para;
00533             editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
00534             editor->pCursors[0].nOffset = 0;
00535             editor->pCursors[1] = editor->pCursors[0];
00536             ME_WrapMarkedParagraphs(editor);
00537             return;
00538           }
00539         }
00540       }
00541       if (i == 0)
00542         run = ME_FindItemFwd(run, diRun);
00543       editor->pCursors[i].pRun = run;
00544       editor->pCursors[i].pPara = ME_GetParagraph(run);
00545       editor->pCursors[i].nOffset = 0;
00546     }
00547   }
00548 }
00549 
00550 
00551 void ME_TabPressedInTable(ME_TextEditor *editor, BOOL bSelectedRow)
00552 {
00553   /* FIXME: Shift tab should move to the previous cell. */
00554   ME_Cursor fromCursor, toCursor;
00555   ME_InvalidateSelection(editor);
00556   {
00557     int from, to;
00558     from = ME_GetCursorOfs(&editor->pCursors[0]);
00559     to = ME_GetCursorOfs(&editor->pCursors[1]);
00560     if (from <= to)
00561     {
00562       fromCursor = editor->pCursors[0];
00563       toCursor = editor->pCursors[1];
00564     } else {
00565       fromCursor = editor->pCursors[1];
00566       toCursor = editor->pCursors[0];
00567     }
00568   }
00569   if (!editor->bEmulateVersion10) /* v4.1 */
00570   {
00571     if (!ME_IsInTable(toCursor.pRun))
00572     {
00573       editor->pCursors[0] = toCursor;
00574       editor->pCursors[1] = toCursor;
00575     } else {
00576       ME_SelectOrInsertNextCell(editor, toCursor.pRun);
00577     }
00578   } else { /* v1.0 - 3.0 */
00579     if (!ME_IsInTable(fromCursor.pRun)) {
00580       editor->pCursors[0] = fromCursor;
00581       editor->pCursors[1] = fromCursor;
00582       /* FIXME: For some reason the caret is shown at the start of the
00583        *        previous paragraph in v1.0 to v3.0, and bCaretAtEnd only works
00584        *        within the paragraph for wrapped lines. */
00585       if (ME_FindItemBack(fromCursor.pRun, diRun))
00586         editor->bCaretAtEnd = TRUE;
00587     } else if ((bSelectedRow || !ME_IsInTable(toCursor.pRun))) {
00588       ME_SelectOrInsertNextCell(editor, fromCursor.pRun);
00589     } else {
00590       if (ME_IsSelection(editor) && !toCursor.nOffset)
00591       {
00592         ME_DisplayItem *run;
00593         run = ME_FindItemBack(toCursor.pRun, diRunOrParagraphOrEnd);
00594         if (run->type == diRun && run->member.run.nFlags & MERF_TAB)
00595           ME_SelectOrInsertNextCell(editor, run);
00596         else
00597           ME_SelectOrInsertNextCell(editor, toCursor.pRun);
00598       } else {
00599         ME_SelectOrInsertNextCell(editor, toCursor.pRun);
00600       }
00601     }
00602   }
00603   ME_InvalidateSelection(editor);
00604   ME_Repaint(editor);
00605   ITextHost_TxShowCaret(editor->texthost, FALSE);
00606   ME_ShowCaret(editor);
00607   ME_SendSelChange(editor);
00608 }
00609 
00610 /* Make sure the cursor is not in the hidden table row start paragraph
00611  * without a selection. */
00612 void ME_MoveCursorFromTableRowStartParagraph(ME_TextEditor *editor)
00613 {
00614   ME_DisplayItem *para = editor->pCursors[0].pPara;
00615   if (para == editor->pCursors[1].pPara &&
00616       para->member.para.nFlags & MEPF_ROWSTART) {
00617     /* The cursors should not be at the hidden start row paragraph without
00618      * a selection, so the cursor is moved into the first cell. */
00619     para = para->member.para.next_para;
00620     editor->pCursors[0].pPara = para;
00621     editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun);
00622     editor->pCursors[0].nOffset = 0;
00623     editor->pCursors[1] = editor->pCursors[0];
00624   }
00625 }
00626 
00627 struct RTFTable *ME_MakeTableDef(ME_TextEditor *editor)
00628 {
00629   RTFTable *tableDef = ALLOC_OBJ(RTFTable);
00630   ZeroMemory(tableDef, sizeof(RTFTable));
00631   if (!editor->bEmulateVersion10) /* v4.1 */
00632     tableDef->gapH = 10;
00633   return tableDef;
00634 }
00635 
00636 void ME_InitTableDef(ME_TextEditor *editor, struct RTFTable *tableDef)
00637 {
00638   ZeroMemory(tableDef->cells, sizeof(tableDef->cells));
00639   ZeroMemory(tableDef->border, sizeof(tableDef->border));
00640   tableDef->numCellsDefined = 0;
00641   tableDef->leftEdge = 0;
00642   if (!editor->bEmulateVersion10) /* v4.1 */
00643     tableDef->gapH = 10;
00644   else /* v1.0 - 3.0 */
00645     tableDef->gapH = 0;
00646 }

Generated on Sat May 26 2012 04:23:52 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.