1
2 #include <cmath>
3
4 #include "pageitem_noteframe.h"
5
6 #include "appmodes.h"
7 #include "pageitem.h"
8 #include "pageitem_textframe.h"
9
10 #include "scribusdoc.h"
11 #include "undomanager.h"
12 #include "util.h"
13 #include "util_text.h"
14
15 #include "text/boxes.h"
16
PageItem_NoteFrame(NotesStyle * nStyle,ScribusDoc * doc,double x,double y,double w,double h,double w2,const QString & fill,const QString & outline)17 PageItem_NoteFrame::PageItem_NoteFrame(NotesStyle *nStyle, ScribusDoc *doc, double x, double y, double w, double h, double w2, const QString& fill, const QString& outline)
18 : PageItem_TextFrame(doc, x, y, w, h, w2, fill, outline)
19 {
20 m_nstyle = nStyle;
21 itemText.clear();
22
23 m_itemName = generateUniqueCopyName(nStyle->isEndNotes() ? tr("Endnote frame ") + m_nstyle->name() : tr("Footnote frame ") + m_nstyle->name(), false);
24 AutoName = false; //endnotes frame will saved with name
25 setUName(m_itemName);
26
27 //set default style for note frame
28 ParagraphStyle newStyle;
29 if (nStyle->notesParStyle().isEmpty() || (nStyle->notesParStyle() == tr("No Style")))
30 newStyle.setParent(m_Doc->paragraphStyles()[0].name()); // set default doc style
31 else
32 newStyle.setParent(nStyle->notesParStyle());
33 itemText.blockSignals(true);
34 itemText.setDefaultStyle(newStyle);
35 itemText.blockSignals(false);
36
37 m_textFlowMode = TextFlowUsesFrameShape;
38 setColumns(1);
39
40 m_SizeVLocked = m_nstyle->isAutoNotesHeight();
41 m_SizeHLocked = m_nstyle->isAutoNotesWidth();
42 m_SizeLocked = m_nstyle->isAutoNotesHeight() && m_nstyle->isAutoNotesWidth();
43 }
44
PageItem_NoteFrame(ScribusDoc * doc,double x,double y,double w,double h,double w2,const QString & fill,const QString & outline)45 PageItem_NoteFrame::PageItem_NoteFrame(ScribusDoc *doc, double x, double y, double w, double h, double w2, const QString& fill, const QString& outline)
46 : PageItem_TextFrame(doc, x, y, w, h, w2, fill, outline)
47 {
48 m_textFlowMode = TextFlowUsesFrameShape;
49 }
50
PageItem_NoteFrame(PageItem_TextFrame * inFrame,NotesStyle * nStyle)51 PageItem_NoteFrame::PageItem_NoteFrame(PageItem_TextFrame* inFrame, NotesStyle *nStyle) : PageItem_TextFrame(inFrame->doc(),inFrame->xPos(), inFrame->yPos(),inFrame->width(), inFrame->height(),inFrame->lineWidth(), inFrame->fillColor(), inFrame->lineColor())
52 {
53 m_nstyle = nStyle;
54 m_masterFrame = inFrame;
55
56 m_itemName = generateUniqueCopyName(nStyle->isEndNotes() ? tr("Endnote frame ") + m_nstyle->name() : tr("Footnote frame ") + m_nstyle->name(), false);
57 AutoName = false;
58 setUName(m_itemName);
59
60 //set default style for note frame
61 ParagraphStyle newStyle;
62 if (nStyle->notesParStyle().isEmpty() || (nStyle->notesParStyle() == tr("No Style")))
63 {
64 if (nStyle->isEndNotes())
65 //set default doc style
66 newStyle.setParent(m_Doc->paragraphStyles()[0].name());
67 else
68 {
69 newStyle.setParent(m_masterFrame->itemText.defaultStyle().parent());
70 newStyle.applyStyle(m_masterFrame->currentStyle());
71 }
72 }
73 else
74 newStyle.setParent(nStyle->notesParStyle());
75 itemText.blockSignals(true);
76 itemText.setDefaultStyle(newStyle);
77 itemText.blockSignals(false);
78
79 double frameHeight = calculateLineSpacing(newStyle, this);
80 if (frameHeight == 0.0 && !m_nstyle->isAutoNotesHeight())
81 frameHeight = newStyle.charStyle().fontSize()/10;
82 m_height = oldHeight = frameHeight;
83 oldWidth = m_width;
84 oldRot = m_rotation;
85 oldXpos = m_xPos;
86 m_yPos = oldYpos = m_masterFrame->yPos() + m_masterFrame->height();
87
88 m_textFlowMode = TextFlowUsesFrameShape;
89 setColumns(1);
90
91 if (m_nstyle->isAutoWeldNotesFrames() && (m_masterFrame != nullptr))
92 {
93 addWelded(m_masterFrame);
94 m_masterFrame->addWelded(this);
95 m_masterFrame->setWeldPoint(0, m_masterFrame->height(), this);
96 setWeldPoint(0,0, m_masterFrame);
97 }
98 if (m_nstyle->isAutoNotesHeight())
99 m_SizeVLocked = true;
100 else
101 m_SizeVLocked = false;
102 if (m_nstyle->isAutoNotesWidth())
103 m_SizeHLocked = true;
104 else
105 m_SizeHLocked = false;
106 if (m_nstyle->isAutoNotesHeight() && m_nstyle->isAutoNotesWidth())
107 m_SizeLocked = true;
108 else
109 m_SizeLocked = false;
110 }
111
getNamedResources(ResourceCollection & lists) const112 void PageItem_NoteFrame::getNamedResources(ResourceCollection& lists) const
113 {
114 PageItem_TextFrame::getNamedResources(lists);
115
116 if (m_nstyle)
117 lists.collectNoteStyle(m_nstyle->name());
118 }
119
replaceNamedResources(ResourceCollection & newNames)120 void PageItem_NoteFrame::replaceNamedResources(ResourceCollection& newNames)
121 {
122 PageItem_TextFrame::replaceNamedResources(newNames);
123
124 if (m_nstyle)
125 {
126 const auto& rsrcNoteStyles = newNames.noteStyles();
127 auto it = rsrcNoteStyles.find(m_nstyle->name());
128 if ((it != rsrcNoteStyles.end()) && (*it != m_nstyle->name()))
129 {
130 NotesStyle* newStyle = m_Doc->getNotesStyle(*it);
131 setNoteStyle(newStyle);
132 }
133 }
134 }
135
setNoteStyle(NotesStyle * nStyle,PageItem_TextFrame * master)136 void PageItem_NoteFrame::setNoteStyle(NotesStyle *nStyle, PageItem_TextFrame* master)
137 {
138 m_nstyle = nStyle;
139 if (master != nullptr)
140 m_masterFrame = master;
141 itemText.clear();
142
143 m_itemName = generateUniqueCopyName(m_nstyle->isEndNotes() ? "Endnote frame " + m_nstyle->name() : "Footnote frame " + m_nstyle->name(), false);
144 setUName(m_itemName);
145
146 //set default style for note frame
147 ParagraphStyle newStyle;
148 if (nStyle->notesParStyle().isEmpty() || (nStyle->notesParStyle() == tr("No Style")))
149 {
150 if (nStyle->isEndNotes() || (m_masterFrame == nullptr))
151 {
152 //set default doc style
153 newStyle.setParent(m_Doc->paragraphStyles()[0].name());
154 }
155 else if (master != nullptr)
156 {
157 newStyle.setParent(m_masterFrame->itemText.defaultStyle().parent());
158 newStyle.applyStyle(m_masterFrame->currentStyle());
159 }
160 }
161 else
162 newStyle.setParent(nStyle->notesParStyle());
163 itemText.blockSignals(true);
164 itemText.setDefaultStyle(newStyle);
165 itemText.blockSignals(false);
166
167 if (m_nstyle->isAutoNotesHeight())
168 m_SizeVLocked = true;
169 else
170 m_SizeVLocked = false;
171 if (m_nstyle->isAutoNotesWidth())
172 m_SizeHLocked = true;
173 else
174 m_SizeHLocked = false;
175 if (m_nstyle->isAutoNotesHeight() && m_nstyle->isAutoNotesWidth())
176 m_SizeLocked = true;
177 else
178 m_SizeLocked = false;
179 }
180
layout()181 void PageItem_NoteFrame::layout()
182 {
183 if (!invalid || m_notes.isEmpty())
184 return;
185 if (!m_Doc->flag_layoutNotesFrames)
186 return;
187 if (itemText.length() == 0)
188 return;
189 if ((m_masterFrame != nullptr) && m_masterFrame->invalid)
190 return;
191
192 //while layouting notes frames undo should be disabled
193 UndoManager::instance()->setUndoEnabled(false);
194
195 if (m_nstyle->isAutoNotesWidth() && (m_width != m_masterFrame->width()))
196 {
197 oldWidth = m_width = m_masterFrame->width();
198 updateClip();
199 }
200
201 if ((m_Doc->appMode == modeEdit) && isSelected())
202 updateNotesText();
203
204 PageItem_TextFrame::layout();
205 int oldH = m_height;
206 if (notesStyle()->isAutoNotesHeight())
207 {
208 if (frameOverflows())
209 {
210 // Increase height while text don`t fit in frame
211 double maxH = m_Doc->currentPage()->height() - m_yPos;
212 if (maxH <= 0)
213 maxH = m_Doc->currentPage()->height();
214 while (frameOverflows())
215 {
216 oldHeight = m_height += 8;
217 updateClip(false);
218 invalid = true;
219 PageItem_TextFrame::layout();
220 if (m_height >= maxH)
221 break;
222 }
223 }
224 textLayout.box()->moveTo(textLayout.box()->x(), 0);
225 oldHeight = m_height = textLayout.box()->naturalHeight() + m_textDistanceMargins.bottom();
226 updateConstants();
227 updateClip();
228 invalid = true;
229 PageItem_TextFrame::layout();
230 }
231 if (oldH != height())
232 {
233 if (masterFrame() != nullptr)
234 {
235 foreach(PageItem_NoteFrame* nF, masterFrame()->notesFramesList())
236 nF->invalid = true;
237 }
238 }
239 invalid = false;
240 m_Doc->regionsChanged()->update(getBoundingRect());
241 UndoManager::instance()->setUndoEnabled(true);
242 }
243
insertNote(TextNote * note)244 void PageItem_NoteFrame::insertNote(TextNote *note)
245 {
246 Mark* mrk = note->noteMark();
247 if (mrk == nullptr)
248 {
249 mrk = m_Doc->newMark();
250 mrk->setType(MARKNoteFrameType);
251 QString label = "NoteFrameMark_" + notesStyle()->name();
252 if (notesStyle()->range() == NSRstory)
253 label += " in " + note->masterMark()->getItemPtr()->firstInChain()->itemName();
254 mrk->label = label + "_" + note->numString();
255 mrk->setNotePtr(note);
256 getUniqueName(mrk->label, m_Doc->marksLabelsList(MARKNoteFrameType), "_");
257 note->setNoteMark(mrk);
258 }
259 mrk->setItemPtr(this);
260 mrk->setString(notesStyle()->prefix() + note->numString() + note->notesStyle()->suffix());
261
262 StoryText story(m_Doc);
263 if (!note->saxedText().isEmpty())
264 story = desaxeString(m_Doc, note->saxedText());
265 story.insertMark(mrk, 0);
266 story.setDefaultStyle(itemText.defaultStyle());
267 // story.applyCharStyle(0, story.length(), itemText.charStyle());
268 if (itemText.length() > 0)
269 itemText.insertChars(itemText.length(), SpecialChars::PARSEP);
270 itemText.insert(itemText.length(), story);
271 }
272
updateNotes(const QList<TextNote * > & nList,bool clear)273 void PageItem_NoteFrame::updateNotes(const QList<TextNote*>& nList, bool clear)
274 {
275 if (nList == m_notes && !clear)
276 return;
277 UndoManager::instance()->setUndoEnabled(false);
278 m_Doc->setNotesChanged(true);
279 //itemText.blockSignals(true);
280
281 if (clear)
282 {
283 itemText.selectAll();
284 deleteSelectedTextFromFrame();
285 m_notes = nList;
286 for (int a=0; a < m_notes.count(); ++a)
287 insertNote(m_notes.at(a));
288 }
289 else
290 {
291 //just insert new notes into frame notes list
292 int count = nList.count();
293 if (count > 0)
294 {
295 for (int i=0; i< count; ++i)
296 {
297 TextNote* note = nList.at(i);
298 if (!m_notes.contains(note))
299 {
300 m_notes.append(note);
301 insertNote(note);
302 }
303 }
304 }
305 }
306 UndoManager::instance()->setUndoEnabled(true);
307 //itemText.blockSignals(false);
308 invalid = true;
309 }
310
updateNotesText()311 void PageItem_NoteFrame::updateNotesText()
312 {
313 //read texts from notes frame and copy it to note`s data
314 if (m_notes.isEmpty() || (itemText.length() == 0))
315 return;
316
317 int oldSelStart = itemText.startOfSelection();
318 int oldSelLen = itemText.selectionLength();
319 int pos = 0;
320 int startPos = 0;
321 TextNote *note = nullptr;
322 Mark* prevMrk = nullptr;
323 while (pos < itemText.length())
324 {
325 if (itemText.hasMark(pos))
326 {
327 Mark* mark = itemText.mark(pos);
328 if (mark->isType(MARKNoteFrameType))
329 {
330 if (prevMrk != nullptr)
331 {
332 note = prevMrk->getNotePtr();
333 if (note != nullptr)
334 {
335 int offset = 0;
336 if (itemText.text(pos-1) == SpecialChars::PARSEP)
337 ++offset;
338 int len = pos - startPos -offset;
339 if (len <= 0)
340 note->clearSaxedText();
341 else
342 {
343 note->setSaxedText(getItemTextSaxed(startPos, len));
344 note->textLen = len;
345 }
346 itemText.deselectAll();
347 }
348 }
349 prevMrk = mark;
350 startPos = pos +1;
351 }
352 }
353 ++pos;
354 }
355 if (prevMrk != nullptr)
356 {
357 note = prevMrk->getNotePtr();
358 Q_ASSERT(note != nullptr);
359 if (startPos != pos)
360 {
361 note->setSaxedText(getItemTextSaxed(startPos, pos - startPos));
362 note->textLen = pos - startPos;
363 }
364 else //empty note text (only note marker)
365 note->clearSaxedText();
366 }
367 if (oldSelLen > 0)
368 itemText.select(oldSelStart, oldSelLen);
369 }
370
restoreDeleteNoteText(SimpleState * state,bool isUndo)371 void PageItem_NoteFrame::restoreDeleteNoteText(SimpleState *state, bool isUndo)
372 {
373 PageItem::restoreDeleteFrameText(state, isUndo);
374 updateNotesText();
375 }
376
restoreDeleteNoteParagraph(SimpleState * state,bool isUndo)377 void PageItem_NoteFrame::restoreDeleteNoteParagraph(SimpleState *state, bool isUndo)
378 {
379 PageItem::restoreDeleteFrameParagraph(state, isUndo);
380 updateNotesText();
381 }
382
restoreInsertNoteText(SimpleState * state,bool isUndo)383 void PageItem_NoteFrame::restoreInsertNoteText(SimpleState *state, bool isUndo)
384 {
385 PageItem::restoreInsertFrameText(state, isUndo);
386 updateNotesText();
387 }
388
restoreInsertNoteParagraph(SimpleState * state,bool isUndo)389 void PageItem_NoteFrame::restoreInsertNoteParagraph(SimpleState *state, bool isUndo)
390 {
391 PageItem::restoreInsertFrameParagraph(state, isUndo);
392 updateNotesText();
393 }
394
unWeld(bool doUndo)395 void PageItem_NoteFrame::unWeld(bool doUndo)
396 {
397 if (doUndo)
398 PageItem::unWeld();
399 else
400 {
401 for (int a = 0 ; a < weldList.count(); a++)
402 {
403 WeldingInfo wInf = weldList.at(a);
404 PageItem *pIt = wInf.weldItem;
405 for (int b = 0 ; b < pIt->weldList.count(); b++)
406 {
407 WeldingInfo wInf2 = pIt->weldList.at(b);
408 PageItem *pIt2 = wInf2.weldItem;
409 if (pIt2 == this)
410 {
411 pIt->weldList.removeAt(b);
412 break;
413 }
414 }
415 }
416 weldList.clear();
417 }
418 }
419
findNoteCpos(TextNote * note)420 int PageItem_NoteFrame::findNoteCpos(TextNote* note)
421 {
422 //find position of note in note`s frame
423 if (itemText.length() == 0)
424 return -1;
425 for (int pos=0; pos < itemText.length(); ++pos)
426 {
427 Mark* mark = itemText.mark(pos);
428 if (itemText.hasMark(pos) && mark->isType(MARKNoteFrameType))
429 {
430 if (mark->getNotePtr() == note)
431 return (pos);
432 }
433 }
434 return -1;
435 }
436