Merge branch '2.3.2-staging' into 2.3.x

This commit is contained in:
Richard Heck 2018-04-14 23:52:31 -04:00
commit bcb002039b
135 changed files with 9608 additions and 2497 deletions

View File

@ -16,7 +16,7 @@ EXTRA_DIST = \
1.6.2/src/hunspell/hunvisapi.h.in \ 1.6.2/src/hunspell/hunvisapi.h.in \
1.6.2/src/hunspell/utf_info.cxx 1.6.2/src/hunspell/utf_info.cxx
AM_CPPFLAGS += -DHUNSPELL_STATIC AM_CPPFLAGS += -DHUNSPELL_STATIC @STDLIB_DEBUG@
liblyxhunspell_a_SOURCES = \ liblyxhunspell_a_SOURCES = \
1.6.2/src/hunspell/affentry.cxx \ 1.6.2/src/hunspell/affentry.cxx \

View File

@ -228,6 +228,9 @@ The following options allow you to tweak the generated code more precisely (see
--without-included-boost is specified). You may have to use --without-included-boost is specified). You may have to use
--disable-stdlib-debug when linking development versions against --disable-stdlib-debug when linking development versions against
your system's boost library. your system's boost library.
The same problem applies to hunspell (as of hunspell 1.5). So either
compile --with-included-hunspell or --disable-stdlib-debug when
linking development versions against your system's hunspell library.
o --enable-monolithic-build[=boost,client,insets,mathed,core,tex2lyx,frontend-qt4] o --enable-monolithic-build[=boost,client,insets,mathed,core,tex2lyx,frontend-qt4]
that enables monolithic build of the given parts of the source that enables monolithic build of the given parts of the source

View File

@ -420,6 +420,7 @@ if test x$GXX = xyes; then
lyx_flags="$lyx_flags stdlib-debug" lyx_flags="$lyx_flags stdlib-debug"
AC_DEFINE(_GLIBCXX_DEBUG, 1, [libstdc++ debug mode]) AC_DEFINE(_GLIBCXX_DEBUG, 1, [libstdc++ debug mode])
AC_DEFINE(_GLIBCXX_DEBUG_PEDANTIC, 1, [libstdc++ pedantic debug mode]) AC_DEFINE(_GLIBCXX_DEBUG_PEDANTIC, 1, [libstdc++ pedantic debug mode])
AC_SUBST(STDLIB_DEBUG, "-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC")
;; ;;
esac esac
fi fi

View File

@ -60,6 +60,24 @@ AC_DEFUN([CHECK_WITH_ENCHANT],
fi fi
]) ])
AC_DEFUN([LYX_HAVE_HUNSPELL_CXXABI],
[
AC_MSG_CHECKING([whether hunspell C++ (rather than C) ABI is provided])
save_CXXFLAGS=$CXXFLAGS
CXXFLAGS="$ENCHANT_CFLAGS $AM_CXXFLAGS $CXXFLAGS"
# in the C++ ABI, stem() returns a vector, in the C ABI, it returns an int
AC_TRY_COMPILE([#include <hunspell/hunspell.hxx>],
[Hunspell sp("foo", "bar");
int i = sp.stem("test").size();],
[AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_HUNSPELL_CXXABI, 1, [Define to 1 if hunspell C++ (rather than C) ABI is detected])
have_hunspell_cxx_abi=yes
],
[AC_MSG_RESULT(no)])
CXXFLAGS=$save_CXXFLAGS
])
# Macro to add for using hunspell spellchecker libraries! -*- sh -*- # Macro to add for using hunspell spellchecker libraries! -*- sh -*-
AC_DEFUN([CHECK_WITH_HUNSPELL], AC_DEFUN([CHECK_WITH_HUNSPELL],
[ [
@ -83,6 +101,12 @@ AC_DEFUN([CHECK_WITH_HUNSPELL],
AC_MSG_RESULT(no) AC_MSG_RESULT(no)
fi fi
fi fi
LYX_HAVE_HUNSPELL_CXXABI
if test $enable_stdlib_debug = "yes" -a -n "$have_hunspell_cxx_abi" ; then
LYX_WARNING([Compiling LyX with stdlib-debug and system hunspell libraries may lead to
crashes. Consider using --disable-stdlib-debug or --with-included-hunspell.])
fi
]) ])
dnl Usage: LYX_USE_INCLUDED_HUNSPELL : select if the included hunspell should dnl Usage: LYX_USE_INCLUDED_HUNSPELL : select if the included hunspell should
@ -113,6 +137,7 @@ AC_DEFUN([LYX_CHECK_SPELL_ENGINES],
dnl the user wanted to use the included hunspell, so do not check for external hunspell dnl the user wanted to use the included hunspell, so do not check for external hunspell
lyx_use_hunspell=true lyx_use_hunspell=true
AC_DEFINE(USE_HUNSPELL, 1, [Define as 1 to use the hunspell library]) AC_DEFINE(USE_HUNSPELL, 1, [Define as 1 to use the hunspell library])
AC_DEFINE(HAVE_HUNSPELL_CXXABI, 1, [Define to 1 if hunspell C++ (rather than C) ABI is detected])
lyx_flags="$lyx_flags use-hunspell" lyx_flags="$lyx_flags use-hunspell"
else else
CHECK_WITH_HUNSPELL CHECK_WITH_HUNSPELL

View File

@ -60,38 +60,43 @@ cursor.
* Clean-up of drawing code * Clean-up of drawing code
The goal is to make painting with drawing disable fast enough that it ** Make SinglePar update flag useful again.
can be used after every metrics computation. Then we can separate real
drawing from metrics.
Other changes are only clean-ups. The current code can be very expensive when moving cursor inside a
huge table, for example. We should test the flag again, although this
will probably lead to some glitches here and there.
** Set Row::changed() in a finer way
*** singleParUpdate
When the height of the current paragraph changes, there is no need for
a full screen update. Only the rows after the current one need to have
their position recomputed.
This is also true when scrolling (how to do that?)
*** redoParagraph
It should be possible to check whether the new row is the same as the
old one and keep its changed() status in this case. This would reduce
a lot the amount of stuff to redraw.
** Put labels and friends in the Row as elements
It should not be necessary to access the Paragraph object to draw.
Adding the static elements to Row is a lot of work, but worth it IMO.
** Create a unique row by paragraph and break it afterwards
This should be a performance gain (only if paragraph breaking still
shows as expensive after the rest is done)
** do not add the vertical margin of main text to first/last row
Would make code cleaner. Probably no so difficult.
** When a paragraph ends with a newline, compute correctly the height of the extra row. ** When a paragraph ends with a newline, compute correctly the height of the extra row.
** Rewrite TextMetrics::editXY, checkInsetHit using row information (getPosNearX)?
The helper version should return a Row::Element instead of an InsetTable.
** Set inset position during metrics phase
In order to do that, a no-paint drawing will be initiated after every
redoParagraph. This code path will need to be made as fast as possible.
Effect: avoid depending on actual drawing having taken place. In turn,
it will allow to do drawing on paint events, like any reasonable
application would do.
** Cleanup after complete metrics
Then the following can be done:
+ remove hack in InsetMathNest::drawSelection
+ remove painting when not inside in drawParagraph
+ remove Cursor::inCoordCache?
** Paint directly to screen
Instead of using an intermediary pixmap. I have no idea of how
difficult it will prove.
One benefit will be that subpixel aliasing will work again (#9972)
** Merging bv::updateMetrics and tm::metrics ** Merging bv::updateMetrics and tm::metrics
While the full metrics computation tries hard to limit the number of While the full metrics computation tries hard to limit the number of
@ -101,25 +106,25 @@ insets. We should re-use the bv::updateMetrics logic:
+ transfer all the logic of bv::updateMetrics to tm. + transfer all the logic of bv::updateMetrics to tm.
+ Main InsetText should not be special. + Main InsetText should not be special.
The difficuly for a tall table cell for example, is that it may be The difficulty for a tall table cell for example, is that it may be
necessary to break the whole contents to know the width of the cell. necessary to break the whole contents to know the width of the cell.
* Description of current drawing mechanism * Description of current drawing mechanism
** Two stage drawing ** Three-stage drawing
There are two parts to drawing the work area: There are three parts to drawing the work area:
+ the metrics phase computes the size of insets and breaks the + the metrics phase computes the size of insets and breaks the
paragraphs into rows. It stores the dimension of insets (both paragraphs into rows. It stores the dimension of insets (both
normal and math) in bv::coordCache. normal and math) in bv::coordCache.
+ the drawing phase draws the contents and caches the inset + the nodraw drawing phase paints the screen (see below) with a null
positions. Since the caching of positions is useful in itself, painter. The only useful effect is to store the inset positions.
there is a provision for drawing "without" drawing when the only
thing we want is to cache inset positions + an update() signal is sent. This in turn will trigger a paint
(Painter::setDrawingEnabled). event, and the actual screen painting will happen then.
The machinery is controlled via bv::processUpdateFlags. This method is The machinery is controlled via bv::processUpdateFlags. This method is
called at the end of bv::mouseEventDispatch and in called at the end of bv::mouseEventDispatch and in
@ -138,25 +143,37 @@ DecorationUpdate). It triggers a recomputation of the metrics when either:
existing metrics. Note that the Update::SinglePar flag is *never* existing metrics. Note that the Update::SinglePar flag is *never*
taken into account. taken into account.
If a computation of metrics has taken place, Force is removed from the
flags and ForceDraw is added instead.
It is OK to call processUptateFlags several times before an update. In
this case, the effects are cumulative.processUpdateFlags execute the
metrics-related actions, but defers the actual drawing to the next
paint event.
The screen is drawn (with appropriate update strategy), except when The screen is drawn (with appropriate update strategy), except when
update flag is Update::None. update flag is Update::None.
** Metrics computation ** Metrics computation (and nodraw drawing phase)
This is triggered by bv::updateMetrics, which calls tm::redoParagraph for This is triggered by bv::updateMetrics, which calls tm::redoParagraph for
all visible paragraphs. Paragraphs above or below the screen (needed all visible paragraphs. Some Paragraphs above or below the screen (needed
for page up/down) and computed as needed. for page up/down) and computed as needed.
tm::redoParagraph will call Inset::metrics for each inset. In the case tm::redoParagraph will call Inset::metrics for each inset. In the case
of text insets, this will invoke recursively tm::metrics, which redoes of text insets, this will invoke recursively tm::metrics, which redoes
all the paragraphs of the inset. all the paragraphs of the inset.
At the end of the function, bv::updatePosCache is called. It triggers
a repaint of the document with a NullPainter (a painter that does
nothing). This has the effect of caching all insets positions.
** Drawing the work area. ** Drawing the work area.
This is done in bv::draw. This method is triggered mainly by This is done in bv::draw. This method is triggered by a paint event,
Buffer::changed, which draws all the work areas that show the given buffer. mainly called through Buffer::changed, which draws all the work areas
that show the given buffer.
Note that, When Buffer::changed is called outside of Note that, When Buffer::changed is called outside of
bv::processUpdateFlags, it is not clear whether the update strategy bv::processUpdateFlags, it is not clear whether the update strategy
@ -186,3 +203,6 @@ The action depends on the update strategy:
+ SingleParUpdate: only tries to repaint current paragraph in a way + SingleParUpdate: only tries to repaint current paragraph in a way
that is not yet very clear to me. that is not yet very clear to me.
BufferView::draw can also be called with a null painter from
BufferView::updateMetrics().

View File

@ -72,6 +72,36 @@ check_type_size("long long" HAVE_LONG_LONG)
check_type_size(wchar_t HAVE_WCHAR_T) check_type_size(wchar_t HAVE_WCHAR_T)
check_type_size(wint_t HAVE_WINT_T) check_type_size(wint_t HAVE_WINT_T)
if(HUNSPELL_FOUND)
# check whether hunspell C++ (rather than C) ABI is provided
set(HunspellTestFile "${CMAKE_BINARY_DIR}/hunspelltest.cpp")
file(WRITE "${HunspellTestFile}"
"
#include <hunspell/hunspell.hxx>
int main()
{
Hunspell sp(\"foo\", \"bar\");
int i = sp.stem(\"test\").size();
return(0);
}
"
)
try_compile(HAVE_HUNSPELL_CXXABI
"${CMAKE_BINARY_DIR}"
"${HunspellTestFile}"
CMAKE_FLAGS
"-DINCLUDE_DIRECTORIES:STRING=${HUNSPELL_INCLUDE_DIR}"
"-DCMAKE_CXX_LINK_EXECUTABLE='${CMAKE_COMMAD} echo not linking now...'"
OUTPUT_VARIABLE LOG2)
message(STATUS "HAVE_HUNSPELL_CXXABI = ${HAVE_HUNSPELL_CXXABI}")
#message(STATUS "LOG2 = ${LOG2}")
if(LYX_EXTERNAL_HUNSPELL AND LYX_STDLIB_DEBUG AND HAVE_HUNSPELL_CXXABI)
message(WARNING "Compiling LyX with stdlib-debug and system hunspell libraries may lead to crashes. Consider using -DLYX_STDLIB_DEBUG=OFF or -DLYX_EXTERNAL_HUNSPELL=OFF.")
endif()
endif()
#check_cxx_source_compiles( #check_cxx_source_compiles(
# " # "

View File

@ -66,6 +66,9 @@
#define HAVE_ALLOCA #define HAVE_ALLOCA
#endif #endif
/* whether hunspell C++ (rather than C) ABI is provided */
#cmakedefine HAVE_HUNSPELL_CXXABI 1
#cmakedefine HAVE_ICONV_CONST 1 #cmakedefine HAVE_ICONV_CONST 1
#ifdef HAVE_ICONV_CONST #ifdef HAVE_ICONV_CONST
#define ICONV_CONST const #define ICONV_CONST const

View File

@ -118,6 +118,9 @@
@bMin Ding @bMin Ding
@iE-mail: u5032331 () uds ! anu ! edu ! au @iE-mail: u5032331 () uds ! anu ! edu ! au
Chinese (simplified) translations Chinese (simplified) translations
@bAlexander Dunlap
@iE-mail: alexander.dunlap () gmail ! com
Improvement to recent files support
@bAnders Ekberg @bAnders Ekberg
@iE-mail: anek () chalmers ! se @iE-mail: anek () chalmers ! se
Improvements to the Swedish translation of the Windows Installer Improvements to the Swedish translation of the Windows Installer

View File

@ -111,6 +111,10 @@
opened in editable mode. This state used to be hardcoded at compile opened in editable mode. This state used to be hardcoded at compile
time. time.
* buffer-anonymize (2.3.2)
Replace all text n the document by streams of `a'. This is useful
for sharing private documents in a bug report.
* font-crossout * font-crossout
Cross out characters. Cross out characters.

View File

@ -768,10 +768,10 @@ def checkFormatEntries(dtl_tools):
def checkConverterEntries(): def checkConverterEntries():
''' Check all converters (\converter entries) ''' ''' Check all converters (\converter entries) '''
checkProg('the pdflatex program', ['pdflatex $$i'], checkProg('the pdflatex program', ['pdflatex $$i'],
rc_entry = [ r'\converter pdflatex pdf2 "%%" "latex=pdflatex"' ]) rc_entry = [ r'\converter pdflatex pdf2 "%%" "latex=pdflatex,hyperref-driver=pdftex"' ])
checkProg('XeTeX', ['xelatex $$i'], checkProg('XeTeX', ['xelatex $$i'],
rc_entry = [ r'\converter xetex pdf4 "%%" "latex=xelatex"' ]) rc_entry = [ r'\converter xetex pdf4 "%%" "latex=xelatex,hyperref-driver=xetex"' ])
checkLuatex() checkLuatex()
@ -923,7 +923,7 @@ def checkConverterEntries():
rc_entry = [ r'\converter rtf html "%%" ""' ]) rc_entry = [ r'\converter rtf html "%%" ""' ])
# Do not define a converter to pdf6, ps is a pure export format # Do not define a converter to pdf6, ps is a pure export format
checkProg('a PS to PDF converter', ['ps2pdf $$i $$o'], checkProg('a PS to PDF converter', ['ps2pdf $$i $$o'],
rc_entry = [ r'\converter ps pdf "%%" ""' ]) rc_entry = [ r'\converter ps pdf "%%" "hyperref-driver=dvips"' ])
# #
checkProg('a PS to TXT converter', ['pstotext $$i > $$o'], checkProg('a PS to TXT converter', ['pstotext $$i > $$o'],
rc_entry = [ r'\converter ps text2 "%%" ""' ]) rc_entry = [ r'\converter ps text2 "%%" ""' ])
@ -973,13 +973,13 @@ def checkConverterEntries():
rc_entry = [ r'\converter dvi text4 "%%" ""' ]) rc_entry = [ r'\converter dvi text4 "%%" ""' ])
# #
checkProg('a DVI to PS converter', ['dvips -o $$o $$i'], checkProg('a DVI to PS converter', ['dvips -o $$o $$i'],
rc_entry = [ r'\converter dvi ps "%%" ""' ]) rc_entry = [ r'\converter dvi ps "%%" "hyperref-driver=dvips"' ])
# #
checkProg('a DVI to cropped EPS converter', ['dvips -E -o $$o $$i'], checkProg('a DVI to cropped EPS converter', ['dvips -E -o $$o $$i'],
rc_entry = [ r'\converter dvi eps3 "%%" ""' ]) rc_entry = [ r'\converter dvi eps3 "%%" ""' ])
# #
checkProg('a DVI to PDF converter', ['dvipdfmx -o $$o $$i', 'dvipdfm -o $$o $$i'], checkProg('a DVI to PDF converter', ['dvipdfmx', 'dvipdfm'],
rc_entry = [ r'\converter dvi pdf3 "%%" ""' ]) rc_entry = [ r'\converter dvi pdf3 "%% -o $$o $$i" "hyperref-driver=%%"' ])
# #
checkProg('a fax program', ['kdeprintfax $$i', 'ksendfax $$i', 'hylapex $$i'], checkProg('a fax program', ['kdeprintfax $$i', 'ksendfax $$i', 'hylapex $$i'],
rc_entry = [ r'\converter ps fax "%%" ""']) rc_entry = [ r'\converter ps fax "%%" ""'])

View File

@ -124,11 +124,12 @@ logicalmkup
\papercolumns 1 \papercolumns 1
\papersides 2 \papersides 2
\paperpagestyle headings \paperpagestyle headings
\tracking_changes false \tracking_changes true
\output_changes false \output_changes false
\html_math_output 0 \html_math_output 0
\html_css_as_file 0 \html_css_as_file 0
\html_be_strict true \html_be_strict true
\author -712698321 "Jürgen Spitzmüller"
\end_header \end_header
\begin_body \begin_body
@ -2515,6 +2516,35 @@ value
format: format:
\end_layout \end_layout
\begin_layout Labeling
\labelwidthstring 00.00.0000
\change_inserted -712698321 1523206314
\begin_inset Flex Code
status collapsed
\begin_layout Plain Layout
\change_inserted -712698321 1523206193
hyperref-driver
\end_layout
\end_inset
The name of the driver that needs to be loaded with the
\family sans
hyperref
\family default
package for this converter.
The loading of the correct driver is necessary to get some PDF-specific
features.
See the
\family sans
hyperref
\family default
manual for details.
\end_layout
\begin_layout Labeling \begin_layout Labeling
\labelwidthstring 00.00.0000 \labelwidthstring 00.00.0000
\begin_inset Flex Code \begin_inset Flex Code
@ -2622,8 +2652,34 @@ $$b
\end_layout \end_layout
\begin_layout Standard \begin_layout Standard
None of these last three are presently used in any of the converters that
are installed with \SpecialChar LyX \change_inserted -712698321 1523206384
A suitable hyperref-driver is set for some converters that are installed
with \SpecialChar LyX
.
\change_deleted -712698321 1523206388
None of these
\change_inserted -712698321 1523206389
The
\change_unchanged
last three
\change_inserted -712698321 1523206400
flags, however,
\change_unchanged
are presently
\change_inserted -712698321 1523206407
not
\change_unchanged
used in any of the
\change_inserted -712698321 1523206437
pre-installed
\change_unchanged
converters
\change_deleted -712698321 1523206442
that are installed with \SpecialChar LyX
\change_unchanged
. .
\end_layout \end_layout

View File

@ -145,6 +145,7 @@ enumitem
\html_math_output 0 \html_math_output 0
\html_css_as_file 0 \html_css_as_file 0
\html_be_strict true \html_be_strict true
\author 5863208 "ab"
\end_header \end_header
\begin_body \begin_body
@ -19952,6 +19953,24 @@ LyX options
tab. tab.
Joining an existing group can be done using the context menu of the image Joining an existing group can be done using the context menu of the image
and checking the name of the desired group. and checking the name of the desired group.
\change_inserted 5863208 1518729806
If there are too many images which need to be assigned to a single group
you can simply put all of them into single selection and choose
\family sans
Unify
\begin_inset space ~
\end_inset
Graphics
\begin_inset space ~
\end_inset
Groups
\family default
in context menu.
\change_unchanged
\end_layout \end_layout
\begin_layout Section \begin_layout Section

View File

@ -1989,6 +1989,25 @@ key=value
\begin_layout Labeling \begin_layout Labeling
\labelwidthstring 00.00.0000 \labelwidthstring 00.00.0000
\family typewriter
hyperref-driver
\family default
Der Name der Treiberdatei, die für diesen Konverter mit dem
\family sans
Hyperref
\family default
-Paket geladen werden soll.
Dies ist nötig, um bestimmte PDF-Features verwenden zu können.
Konsultieren Sie das
\family sans
Hyperref
\family default
-Handbuch für Einzelheiten.
\end_layout
\begin_layout Labeling
\labelwidthstring 00.00.0000
\family typewriter \family typewriter
parselog parselog
\family default \family default
@ -2082,9 +2101,11 @@ index
\end_layout \end_layout
\begin_layout Standard \begin_layout Standard
Keines dieser Flags wird zur Zeit in einem Konverter benutzt, der zusammen Ein passender Hyperref-Treiber wird für einige mit \SpecialChar LyX
mit \SpecialChar LyX installierten Konverter
installiert wird. definiert.
Die zuletzt aufgeführten drei Flags hingegen werden zurzeit von keinem
der vorinstallierten Konverter verwendet.
\end_layout \end_layout
\begin_layout Standard \begin_layout Standard

View File

@ -647,6 +647,14 @@ contributors = [
"27 April 2014", "27 April 2014",
u"Chinese (simplified) translations"), u"Chinese (simplified) translations"),
contributor(u"Alexander Dunlap",
"alexander.dunlap () gmail ! com",
"GPL",
"licensing statement",
"m=151914230920804",
"20 February 2018",
u"Improvement to recent files support"),
contributor(u"Anders Ekberg", contributor(u"Anders Ekberg",
"anek () chalmers ! se", "anek () chalmers ! se",
"GPL", "GPL",

View File

@ -364,6 +364,7 @@ Style Bibliography
Size Larger Size Larger
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -177,6 +177,7 @@ Style Bibliography
Size Huge Size Huge
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -228,5 +228,6 @@ Style Bibliography
Size Larger Size Larger
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -226,4 +226,5 @@ Style Bibliography
Shape Smallcaps Shape Smallcaps
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -1126,6 +1126,7 @@ Style Bibliography
Size Larger Size Larger
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -126,6 +126,7 @@ Style Bibliography
Size Larger Size Larger
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -596,6 +596,7 @@ Style Bibliography
Series Bold Series Bold
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -326,5 +326,6 @@ Style Bibliography
Size Larger Size Larger
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -468,4 +468,5 @@ Style Bibliography
Size Larger Size Larger
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -481,4 +481,5 @@ Style Bibliography
Size Larger Size Larger
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -288,6 +288,7 @@ Style "Bibliography (plain)"
Size Larger Size Larger
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -289,5 +289,6 @@ Style Bibliography
Size Larger Size Larger
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -367,4 +367,5 @@ Style References
Series Bold Series Bold
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -288,6 +288,7 @@ Style Bibliography
Series Bold Series Bold
EndFont EndFont
TocLevel 0 TocLevel 0
IsTocCaption 0
End End

View File

@ -520,6 +520,7 @@ Style Bibliography
Family Sans Family Sans
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End
Style Recipient Style Recipient

View File

@ -371,7 +371,8 @@ Style Bibliography
LabelType Bibliography LabelType Bibliography
LabelString "" LabelString ""
LabelBottomSep 0 LabelBottomSep 0
TocLevel 1 TocLevel 1
IsTocCaption 0
End End
### ###

View File

@ -349,6 +349,7 @@ Style Bibliography
Shape Smallcaps Shape Smallcaps
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End
NoStyle Chapter NoStyle Chapter

View File

@ -165,4 +165,5 @@ Style Bibliography
Size Tiny Size Tiny
EndFont EndFont
TocLevel 1 TocLevel 1
IsTocCaption 0
End End

View File

@ -82,4 +82,5 @@ Style Bibliography
span.bibitemlabel:after { content: "] "; } span.bibitemlabel:after { content: "] "; }
EndHTMLStyle EndHTMLStyle
TocLevel 1 TocLevel 1
ISTocCaption 0
End End

View File

@ -594,6 +594,7 @@ Style Bibliography
Series Bold Series Bold
EndFont EndFont
TocLevel 0 TocLevel 0
IsTocCaption 0
End End
Style Description Style Description

View File

@ -705,7 +705,6 @@ $$
\vspace{} \vspace{}
\vspace*{} \vspace*{}
\whiledo{}{} \whiledo{}{}
\xymatrix{} % this is basically an array => the contents would be parsed badly (bug 8396)
% LaTeX environments. % LaTeX environments.
% They have always one extra "argument": % They have always one extra "argument":

View File

@ -358,6 +358,7 @@ Menuset
Item "Apply Last Text Style|A" "textstyle-apply" Item "Apply Last Text Style|A" "textstyle-apply"
Submenu "Text Style|x" "edit_textstyles" Submenu "Text Style|x" "edit_textstyles"
Item "Paragraph Settings...|P" "layout-paragraph" Item "Paragraph Settings...|P" "layout-paragraph"
OptItem "Unify Graphics Groups|U" "graphics-unify"
LanguageSelector LanguageSelector
Separator Separator
Item "Fullscreen Mode" "ui-toggle fullscreen" Item "Fullscreen Mode" "ui-toggle fullscreen"

View File

@ -2626,15 +2626,16 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
flag.setOnOff(params().output_changes); flag.setOnOff(params().output_changes);
break; break;
case LFUN_BUFFER_TOGGLE_COMPRESSION: { case LFUN_BUFFER_TOGGLE_COMPRESSION:
flag.setOnOff(params().compressed); flag.setOnOff(params().compressed);
break; break;
}
case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC: { case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC:
flag.setOnOff(params().output_sync); flag.setOnOff(params().output_sync);
break; break;
}
case LFUN_BUFFER_ANONYMIZE:
break;
default: default:
return false; return false;
@ -2664,7 +2665,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
string const argument = to_utf8(func.argument()); string const argument = to_utf8(func.argument());
// We'll set this back to false if need be. // We'll set this back to false if need be.
bool dispatched = true; bool dispatched = true;
undo().beginUndoGroup(); // This handles undo groups automagically
UndoGroupHelper ugh(this);
switch (func.action()) { switch (func.action()) {
case LFUN_BUFFER_TOGGLE_READ_ONLY: case LFUN_BUFFER_TOGGLE_READ_ONLY:
@ -2907,12 +2909,20 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
params().output_sync = !params().output_sync; params().output_sync = !params().output_sync;
break; break;
case LFUN_BUFFER_ANONYMIZE: {
undo().recordUndoFullBuffer(CursorData());
CursorData cur(doc_iterator_begin(this));
for ( ; cur ; cur.forwardPar())
cur.paragraph().anonymize();
dr.forceBufferUpdate();
break;
}
default: default:
dispatched = false; dispatched = false;
break; break;
} }
dr.dispatched(dispatched); dr.dispatched(dispatched);
undo().endUndoGroup();
} }
@ -3185,9 +3195,27 @@ vector<docstring> const Buffer::prepareBibFilePaths(OutputParams const & runpara
string utf8input = to_utf8(it->first); string utf8input = to_utf8(it->first);
string database = string database =
prepareFileNameForLaTeX(utf8input, ".bib", runparams.nice); prepareFileNameForLaTeX(utf8input, ".bib", runparams.nice);
FileName const try_in_file = FileName try_in_file =
makeAbsPath(database + ".bib", filePath()); makeAbsPath(database + ".bib", filePath());
bool const not_from_texmf = try_in_file.isReadableFile(); bool not_from_texmf = try_in_file.isReadableFile();
// If the file has not been found, try with the real file name
// (it might come from a child in a sub-directory)
if (!not_from_texmf) {
try_in_file = it->second;
if (try_in_file.isReadableFile()) {
// Check if the file is in texmf
FileName kpsefile(findtexfile(changeExtension(utf8input, "bib"), "bib", true));
not_from_texmf = kpsefile.empty()
|| kpsefile.absFileName() != try_in_file.absFileName();
if (not_from_texmf)
// If this exists, make path relative to the master
// FIXME Unicode
database = removeExtension(
prepareFileNameForLaTeX(to_utf8(makeRelPath(from_utf8(try_in_file.absFileName()),
from_utf8(filePath()))),
".bib", runparams.nice));
}
}
if (!runparams.inComment && !runparams.dryrun && !runparams.nice && if (!runparams.inComment && !runparams.dryrun && !runparams.nice &&
not_from_texmf) { not_from_texmf) {
@ -4301,6 +4329,7 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir
return ExportNoPathToFormat; return ExportNoPathToFormat;
} }
runparams.flavor = converters.getFlavor(path, this); runparams.flavor = converters.getFlavor(path, this);
runparams.hyperref_driver = converters.getHyperrefDriver(path);
Graph::EdgePath::const_iterator it = path.begin(); Graph::EdgePath::const_iterator it = path.begin();
Graph::EdgePath::const_iterator en = path.end(); Graph::EdgePath::const_iterator en = path.end();
for (; it != en; ++it) for (; it != en; ++it)
@ -5360,7 +5389,6 @@ void Buffer::Impl::fileExternallyModified(bool const exists)
"checksum unchanged: " << filename); "checksum unchanged: " << filename);
return; return;
} }
lyx_clean = bak_clean = false;
// If the file has been deleted, only mark the file as dirty since it is // If the file has been deleted, only mark the file as dirty since it is
// pointless to prompt for reloading. If later a file is moved into this // pointless to prompt for reloading. If later a file is moved into this
// location, then the externally modified warning will appear then. // location, then the externally modified warning will appear then.

View File

@ -394,7 +394,7 @@ BufferParams::BufferParams()
papersize = PAPER_DEFAULT; papersize = PAPER_DEFAULT;
orientation = ORIENTATION_PORTRAIT; orientation = ORIENTATION_PORTRAIT;
use_geometry = false; use_geometry = false;
biblio_style = "plain"; biblio_style = string();
use_bibtopic = false; use_bibtopic = false;
multibib = string(); multibib = string();
use_indices = false; use_indices = false;
@ -2094,8 +2094,8 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
OutputParams tmp_params = features.runparams(); OutputParams tmp_params = features.runparams();
pdfoptions().writeLaTeX(tmp_params, os, pdfoptions().writeLaTeX(tmp_params, os,
features.isProvided("hyperref")); features.isProvided("hyperref"));
// correctly break URLs with hyperref and dvi output // correctly break URLs with hyperref and dvi/ps output
if (features.runparams().flavor == OutputParams::LATEX if (features.runparams().hyperref_driver == "dvips"
&& features.isAvailable("breakurl")) && features.isAvailable("breakurl"))
os << "\\usepackage{breakurl}\n"; os << "\\usepackage{breakurl}\n";
} else if (features.isRequired("nameref")) } else if (features.isRequired("nameref"))
@ -3426,6 +3426,9 @@ bool BufferParams::addCiteEngine(vector<string> const & engine)
string const & BufferParams::defaultBiblioStyle() const string const & BufferParams::defaultBiblioStyle() const
{ {
if (!biblio_style.empty())
return biblio_style;
map<string, string> const & bs = documentClass().defaultBiblioStyle(); map<string, string> const & bs = documentClass().defaultBiblioStyle();
auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType())); auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
if (cit != bs.end()) if (cit != bs.end())

View File

@ -70,6 +70,7 @@
#include "frontends/Application.h" #include "frontends/Application.h"
#include "frontends/Delegates.h" #include "frontends/Delegates.h"
#include "frontends/FontMetrics.h" #include "frontends/FontMetrics.h"
#include "frontends/NullPainter.h"
#include "frontends/Painter.h" #include "frontends/Painter.h"
#include "frontends/Selection.h" #include "frontends/Selection.h"
@ -227,14 +228,15 @@ enum ScreenUpdateStrategy {
struct BufferView::Private struct BufferView::Private
{ {
Private(BufferView & bv) : update_strategy_(NoScreenUpdate), Private(BufferView & bv) : update_strategy_(FullScreenUpdate),
update_flags_(Update::Force),
wh_(0), cursor_(bv), wh_(0), cursor_(bv),
anchor_pit_(0), anchor_ypos_(0), anchor_pit_(0), anchor_ypos_(0),
inlineCompletionUniqueChars_(0), inlineCompletionUniqueChars_(0),
last_inset_(0), clickable_inset_(false), last_inset_(0), clickable_inset_(false),
mouse_position_cache_(), mouse_position_cache_(),
bookmark_edit_position_(-1), gui_(0), bookmark_edit_position_(-1), gui_(0),
horiz_scroll_offset_(0) horiz_scroll_offset_(0), repaint_caret_row_(false)
{ {
xsel_cache_.set = false; xsel_cache_.set = false;
} }
@ -244,6 +246,8 @@ struct BufferView::Private
/// ///
ScreenUpdateStrategy update_strategy_; ScreenUpdateStrategy update_strategy_;
/// ///
Update::flags update_flags_;
///
CoordCache coord_cache_; CoordCache coord_cache_;
/// Estimated average par height for scrollbar. /// Estimated average par height for scrollbar.
@ -311,6 +315,12 @@ struct BufferView::Private
/// a slice pointing to the start of the row where cursor was /// a slice pointing to the start of the row where cursor was
/// at previous draw event /// at previous draw event
CursorSlice last_row_slice_; CursorSlice last_row_slice_;
/// a slice pointing to where the cursor has been drawn after the current
/// draw() call.
CursorSlice caret_slice_;
/// indicates whether the caret slice needs to be repainted in this draw() run.
bool repaint_caret_row_;
}; };
@ -438,79 +448,85 @@ bool BufferView::needsFitCursor() const
} }
namespace {
// this is for debugging only.
string flagsAsString(Update::flags flags)
{
if (flags == Update::None)
return "None ";
return string((flags & Update::FitCursor) ? "FitCursor " : "")
+ ((flags & Update::Force) ? "Force " : "")
+ ((flags & Update::ForceDraw) ? "ForceDraw " : "")
+ ((flags & Update::SinglePar) ? "SinglePar " : "");
}
}
void BufferView::processUpdateFlags(Update::flags flags) void BufferView::processUpdateFlags(Update::flags flags)
{ {
// This is close to a hot-path. LYXERR(Debug::PAINTING, "BufferView::processUpdateFlags( "
LYXERR(Debug::PAINTING, "BufferView::processUpdateFlags()" << flagsAsString(flags) << ") buffer: " << &buffer_);
<< "[fitcursor = " << (flags & Update::FitCursor)
<< ", forceupdate = " << (flags & Update::Force)
<< ", singlepar = " << (flags & Update::SinglePar)
<< "] buffer: " << &buffer_);
// FIXME Does this really need doing here? It's done in updateBuffer, and
// if the Buffer doesn't need updating, then do the macros?
buffer_.updateMacros();
// Now do the first drawing step if needed. This consists on updating
// the CoordCache in updateMetrics().
// The second drawing step is done in WorkArea::redraw() if needed.
// FIXME: is this still true now that Buffer::changed() is used all over?
// Case when no explicit update is requested. // Case when no explicit update is requested.
if (!flags) { if (flags == Update::None)
return;
// SinglePar is ignored for now (this should probably change). We
// set it ourselves below, at the price of always rebreaking the
// paragraph at cursor. This can be expensive for large tables.
flags = flags & ~Update::SinglePar;
// First check whether the metrics and inset positions should be updated
if (flags & Update::Force) {
// This will update the CoordCache items and replace Force
// with ForceDraw in flags.
updateMetrics(flags);
}
// Then make sure that the screen contains the cursor if needed
if (flags & Update::FitCursor) {
if (needsFitCursor()) {
scrollToCursor(d->cursor_, false);
// Metrics have to be recomputed (maybe again)
updateMetrics(flags);
}
flags = flags & ~Update::FitCursor;
}
// Finally detect whether we can only repaint a single paragraph
if (!(flags & Update::ForceDraw)) {
if (singleParUpdate())
flags = flags | Update::SinglePar;
else
updateMetrics(flags);
}
// Add flags to the the update flags. These will be reset to None
// after the redraw is actually done
d->update_flags_ = d->update_flags_ | flags;
LYXERR(Debug::PAINTING, "Cumulative flags: " << flagsAsString(flags));
// Now compute the update strategy
// Possibly values in flag are None, Decoration, ForceDraw
LATTEST((d->update_flags_ & ~(Update::None | Update::SinglePar
| Update::Decoration | Update::ForceDraw)) == 0);
if (d->update_flags_ & Update::ForceDraw)
d->update_strategy_ = FullScreenUpdate;
else if (d->update_flags_ & Update::Decoration)
d->update_strategy_ = DecorationUpdate;
else if (d->update_flags_ & Update::SinglePar)
d->update_strategy_ = SingleParUpdate;
else {
// no need to redraw anything. // no need to redraw anything.
d->update_strategy_ = NoScreenUpdate; d->update_strategy_ = NoScreenUpdate;
return;
}
if (flags == Update::Decoration) {
d->update_strategy_ = DecorationUpdate;
buffer_.changed(false);
return;
}
if (flags == Update::FitCursor
|| flags == (Update::Decoration | Update::FitCursor)) {
// tell the frontend to update the screen if needed.
if (needsFitCursor()) {
showCursor();
return;
}
if (flags & Update::Decoration) {
d->update_strategy_ = DecorationUpdate;
buffer_.changed(false);
return;
}
// no screen update is needed in principle, but this
// could change if cursor row needs horizontal scrolling.
d->update_strategy_ = NoScreenUpdate;
buffer_.changed(false);
return;
}
bool const full_metrics = flags & Update::Force || !singleParUpdate();
if (full_metrics)
// We have to update the full screen metrics.
updateMetrics();
if (!(flags & Update::FitCursor)) {
// Nothing to do anymore. Trigger a redraw and return
buffer_.changed(false);
return;
}
// updateMetrics() does not update paragraph position
// This is done at draw() time. So we need a redraw!
buffer_.changed(false);
if (needsFitCursor()) {
// The cursor is off screen so ensure it is visible.
// refresh it:
showCursor();
} }
updateHoveredInset(); updateHoveredInset();
// Trigger a redraw.
buffer_.changed(false);
} }
@ -625,8 +641,7 @@ void BufferView::scrollDocView(int const value, bool update)
// If the offset is less than 2 screen height, prefer to scroll instead. // If the offset is less than 2 screen height, prefer to scroll instead.
if (abs(value) <= 2 * height_) { if (abs(value) <= 2 * height_) {
d->anchor_ypos_ -= value; d->anchor_ypos_ -= value;
buffer_.changed(true); processUpdateFlags(Update::Force);
updateHoveredInset();
return; return;
} }
@ -823,12 +838,7 @@ bool BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos,
d->cursor_.setCurrentFont(); d->cursor_.setCurrentFont();
// Do not forget to reset the anchor (see #9912) // Do not forget to reset the anchor (see #9912)
d->cursor_.resetAnchor(); d->cursor_.resetAnchor();
// To center the screen on this new position we need the processUpdateFlags(Update::FitCursor);
// paragraph position which is computed at draw() time.
// So we need a redraw!
buffer_.changed(false);
if (needsFitCursor())
showCursor();
} }
return success; return success;
@ -870,19 +880,15 @@ void BufferView::showCursor()
void BufferView::showCursor(DocIterator const & dit, void BufferView::showCursor(DocIterator const & dit,
bool recenter, bool update) bool recenter, bool update)
{ {
if (scrollToCursor(dit, recenter) && update) { if (scrollToCursor(dit, recenter) && update)
buffer_.changed(true); processUpdateFlags(Update::Force);
updateHoveredInset();
}
} }
void BufferView::scrollToCursor() void BufferView::scrollToCursor()
{ {
if (scrollToCursor(d->cursor_, false)) { if (scrollToCursor(d->cursor_, false))
buffer_.changed(true); processUpdateFlags(Update::Force);
updateHoveredInset();
}
} }
@ -1128,6 +1134,10 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
flag.setEnabled(true); flag.setEnabled(true);
break; break;
case LFUN_GRAPHICS_UNIFY:
flag.setEnabled(cur.selection());
break;
case LFUN_WORD_FINDADV: { case LFUN_WORD_FINDADV: {
FindAndReplaceOptions opt; FindAndReplaceOptions opt;
istringstream iss(to_utf8(cmd.argument())); istringstream iss(to_utf8(cmd.argument()));
@ -1649,6 +1659,45 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
break; break;
} }
case LFUN_GRAPHICS_UNIFY: {
cur.recordUndoFullBuffer();
DocIterator from, to;
from = cur.selectionBegin();
to = cur.selectionEnd();
string const newId = cmd.getArg(0);
bool fetchId = newId.empty(); //if we wait for groupId from first graphics inset
InsetGraphicsParams grp_par;
if (!fetchId)
InsetGraphics::string2params(graphics::getGroupParams(buffer_, newId), buffer_, grp_par);
if (!from.nextInset()) //move to closest inset
from.forwardInset();
while (!from.empty() && from < to) {
Inset * inset = from.nextInset();
if (!inset)
break;
if (inset->lyxCode() == GRAPHICS_CODE) {
InsetGraphics & ig = static_cast<InsetGraphics &>(*inset);
InsetGraphicsParams inspar = ig.getParams();
if (fetchId) {
grp_par = inspar;
fetchId = false;
} else {
grp_par.filename = inspar.filename;
ig.setParams(grp_par);
}
}
from.forwardInset();
}
dr.screenUpdate(Update::Force); //needed if triggered from context menu
break;
}
case LFUN_STATISTICS: { case LFUN_STATISTICS: {
DocIterator from, to; DocIterator from, to;
if (cur.selection()) { if (cur.selection()) {
@ -1708,8 +1757,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
bool const in_texted = cur.inTexted(); bool const in_texted = cur.inTexted();
cur.setCursor(doc_iterator_begin(cur.buffer())); cur.setCursor(doc_iterator_begin(cur.buffer()));
cur.selHandle(false); cur.selHandle(false);
buffer_.changed(true); // Force an immediate computation of metrics because we need it below
updateHoveredInset(); processUpdateFlags(Update::Force);
d->text_metrics_[&buffer_.text()].editXY(cur, p.x_, p.y_, d->text_metrics_[&buffer_.text()].editXY(cur, p.x_, p.y_,
true, act == LFUN_SCREEN_UP); true, act == LFUN_SCREEN_UP);
@ -1743,8 +1792,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
if (scroll_value) if (scroll_value)
scroll(scroll_step * scroll_value); scroll(scroll_step * scroll_value);
} }
buffer_.changed(true); dr.screenUpdate(Update::ForceDraw);
updateHoveredInset();
dr.forceBufferUpdate(); dr.forceBufferUpdate();
break; break;
} }
@ -1974,6 +2022,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
icp["key"] = from_utf8(arg); icp["key"] = from_utf8(arg);
if (!opt1.empty()) if (!opt1.empty())
icp["before"] = from_utf8(opt1); icp["before"] = from_utf8(opt1);
icp["literal"] =
from_ascii(InsetCitation::last_literal ? "true" : "false");
string icstr = InsetCommand::params2string(icp); string icstr = InsetCommand::params2string(icp);
FuncRequest fr(LFUN_INSET_INSERT, icstr); FuncRequest fr(LFUN_INSET_INSERT, icstr);
lyx::dispatch(fr); lyx::dispatch(fr);
@ -2638,7 +2688,7 @@ bool BufferView::singleParUpdate()
// the singlePar optimisation. // the singlePar optimisation.
return false; return false;
d->update_strategy_ = SingleParUpdate; tm.updatePosCache(bottom_pit);
LYXERR(Debug::PAINTING, "\ny1: " << pm.position() - pm.ascent() LYXERR(Debug::PAINTING, "\ny1: " << pm.position() - pm.ascent()
<< " y2: " << pm.position() + pm.descent() << " y2: " << pm.position() + pm.descent()
@ -2649,6 +2699,13 @@ bool BufferView::singleParUpdate()
void BufferView::updateMetrics() void BufferView::updateMetrics()
{
updateMetrics(d->update_flags_);
d->update_strategy_ = FullScreenUpdate;
}
void BufferView::updateMetrics(Update::flags & update_flags)
{ {
if (height_ == 0 || width_ == 0) if (height_ == 0 || width_ == 0)
return; return;
@ -2691,6 +2748,7 @@ void BufferView::updateMetrics()
} }
} }
anchor_pm.setPosition(d->anchor_ypos_); anchor_pm.setPosition(d->anchor_ypos_);
tm.updatePosCache(d->anchor_pit_);
LYXERR(Debug::PAINTING, "metrics: " LYXERR(Debug::PAINTING, "metrics: "
<< " anchor pit = " << d->anchor_pit_ << " anchor pit = " << d->anchor_pit_
@ -2706,6 +2764,7 @@ void BufferView::updateMetrics()
y1 -= pm.descent(); y1 -= pm.descent();
// Save the paragraph position in the cache. // Save the paragraph position in the cache.
pm.setPosition(y1); pm.setPosition(y1);
tm.updatePosCache(pit1);
y1 -= pm.ascent(); y1 -= pm.ascent();
} }
@ -2719,6 +2778,7 @@ void BufferView::updateMetrics()
y2 += pm.ascent(); y2 += pm.ascent();
// Save the paragraph position in the cache. // Save the paragraph position in the cache.
pm.setPosition(y2); pm.setPosition(y2);
tm.updatePosCache(pit2);
y2 += pm.descent(); y2 += pm.descent();
} }
@ -2730,7 +2790,11 @@ void BufferView::updateMetrics()
<< " pit1 = " << pit1 << " pit1 = " << pit1
<< " pit2 = " << pit2); << " pit2 = " << pit2);
d->update_strategy_ = FullScreenUpdate; // metrics is done, full drawing is necessary now
update_flags = (update_flags & ~Update::Force) | Update::ForceDraw;
// Now update the positions of insets in the cache.
updatePosCache();
if (lyxerr.debugging(Debug::WORKAREA)) { if (lyxerr.debugging(Debug::WORKAREA)) {
LYXERR(Debug::WORKAREA, "BufferView::updateMetrics"); LYXERR(Debug::WORKAREA, "BufferView::updateMetrics");
@ -2739,6 +2803,15 @@ void BufferView::updateMetrics()
} }
void BufferView::updatePosCache()
{
// this is the "nodraw" drawing stage: only set the positions of the
// insets in metrics cache.
frontend::NullPainter np;
draw(np, false);
}
void BufferView::insertLyXFile(FileName const & fname) void BufferView::insertLyXFile(FileName const & fname)
{ {
LASSERT(d->cursor_.inTexted(), return); LASSERT(d->cursor_.inTexted(), return);
@ -2873,7 +2946,7 @@ bool BufferView::paragraphVisible(DocIterator const & dit) const
} }
void BufferView::cursorPosAndHeight(Point & p, int & h) const void BufferView::caretPosAndHeight(Point & p, int & h) const
{ {
Cursor const & cur = cursor(); Cursor const & cur = cursor();
Font const font = cur.real_current_font; Font const font = cur.real_current_font;
@ -2946,7 +3019,30 @@ void BufferView::setCurrentRowSlice(CursorSlice const & rowSlice)
} }
void BufferView::checkCursorScrollOffset(PainterInfo & pi) namespace {
bool sliceInRow(CursorSlice const & cs, Text const * text, Row const & row)
{
/* The normal case is the last line. The previous line takes care
* of empty rows (e.g. empty paragraphs). Cursor boundary issues
* are taken care of when setting caret_slice_ in
* BufferView::draw.
*/
return !cs.empty() && cs.text() == text && cs.pit() == row.pit()
&& ((row.pos() == row.endpos() && row.pos() == cs.pos())
|| (row.pos() <= cs.pos() && cs.pos() < row.endpos()));
}
}
bool BufferView::needRepaint(Text const * text, Row const & row) const
{
return d->repaint_caret_row_ && sliceInRow(d->caret_slice_, text, row);
}
void BufferView::checkCursorScrollOffset()
{ {
CursorSlice rowSlice = d->cursor_.bottom(); CursorSlice rowSlice = d->cursor_.bottom();
TextMetrics const & tm = textMetrics(rowSlice.text()); TextMetrics const & tm = textMetrics(rowSlice.text());
@ -2963,35 +3059,6 @@ void BufferView::checkCursorScrollOffset(PainterInfo & pi)
// Set the row on which the cursor lives. // Set the row on which the cursor lives.
setCurrentRowSlice(rowSlice); setCurrentRowSlice(rowSlice);
// If insets referred to by cursor are not all in the cache, the positions
// need to be recomputed.
if (!d->cursor_.inCoordCache()) {
/** FIXME: the code below adds an extraneous computation of
* inset positions, and can therefore be bad for performance
* (think for example about a very large tabular inset.
* Redawing the row where it is means redrawing the whole
* screen).
*
* The bug that this fixes is the following: assume that there
* is a very large math inset. Upon entering the inset, when
* pressing `End', the row is not scrolled and the cursor is
* not visible. The extra row computation makes sure that the
* inset positions are correctly computed and set in the
* cache. This would not happen if we did not have two-stage
* drawing.
*
* A proper fix would be to always have proper inset positions
* at this point.
*/
// Force the recomputation of inset positions
bool const drawing = pi.pain.isDrawingEnabled();
pi.pain.setDrawingEnabled(false);
// No need to care about vertical position.
RowPainter rp(pi, buffer().text(), row, -d->horiz_scroll_offset_, 0);
rp.paintText();
pi.pain.setDrawingEnabled(drawing);
}
// Current x position of the cursor in pixels // Current x position of the cursor in pixels
int cur_x = getPos(d->cursor_).x_; int cur_x = getPos(d->cursor_).x_;
@ -3035,30 +3102,46 @@ void BufferView::checkCursorScrollOffset(PainterInfo & pi)
} }
void BufferView::draw(frontend::Painter & pain) void BufferView::draw(frontend::Painter & pain, bool paint_caret)
{ {
if (height_ == 0 || width_ == 0) if (height_ == 0 || width_ == 0)
return; return;
LYXERR(Debug::PAINTING, "\t\t*** START DRAWING ***"); LYXERR(Debug::PAINTING, (pain.isNull() ? "\t\t--- START NODRAW ---"
: "\t\t*** START DRAWING ***"));
Text & text = buffer_.text(); Text & text = buffer_.text();
TextMetrics const & tm = d->text_metrics_[&text]; TextMetrics const & tm = d->text_metrics_[&text];
int const y = tm.first().second->position(); int const y = tm.first().second->position();
PainterInfo pi(this, pain); PainterInfo pi(this, pain);
/** A repaint of the previous caret row is needed if there is
* caret painted on screen and either
* 1/ a new caret has to be painted at a place different from
* the existing one;
* 2/ there is no need for a caret anymore.
*/
d->repaint_caret_row_ = !d->caret_slice_.empty() &&
((paint_caret && d->cursor_.top() != d->caret_slice_)
|| ! paint_caret);
// Check whether the row where the cursor lives needs to be scrolled. // Check whether the row where the cursor lives needs to be scrolled.
// Update the drawing strategy if needed. // Update the drawing strategy if needed.
checkCursorScrollOffset(pi); checkCursorScrollOffset();
switch (d->update_strategy_) { switch (d->update_strategy_) {
case NoScreenUpdate: case NoScreenUpdate:
// If no screen painting is actually needed, only some the different // no screen painting is actually needed. In nodraw stage
// coordinates of insets and paragraphs needs to be updated. // however, the different coordinates of insets and paragraphs
// needs to be updated.
LYXERR(Debug::PAINTING, "Strategy: NoScreenUpdate"); LYXERR(Debug::PAINTING, "Strategy: NoScreenUpdate");
pi.full_repaint = true; pi.full_repaint = false;
pi.pain.setDrawingEnabled(false); if (pain.isNull()) {
tm.draw(pi, 0, y); pi.full_repaint = true;
tm.draw(pi, 0, y);
} else if (d->repaint_caret_row_) {
pi.full_repaint = false;
tm.draw(pi, 0, y);
}
break; break;
case SingleParUpdate: case SingleParUpdate:
@ -3103,7 +3186,8 @@ void BufferView::draw(frontend::Painter & pain)
} }
break; break;
} }
LYXERR(Debug::PAINTING, "\n\t\t*** END DRAWING ***"); LYXERR(Debug::PAINTING, (pain.isNull() ? "\t\t --- END NODRAW ---"
: "\t\t *** END DRAWING ***"));
// The scrollbar needs an update. // The scrollbar needs an update.
updateScrollbar(); updateScrollbar();
@ -3114,13 +3198,29 @@ void BufferView::draw(frontend::Painter & pain)
for (pit_type pit = firstpm.first; pit <= lastpm.first; ++pit) { for (pit_type pit = firstpm.first; pit <= lastpm.first; ++pit) {
ParagraphMetrics const & pm = tm.parMetrics(pit); ParagraphMetrics const & pm = tm.parMetrics(pit);
if (pm.position() + pm.descent() > 0) { if (pm.position() + pm.descent() > 0) {
if (d->anchor_pit_ != pit
|| d->anchor_ypos_ != pm.position())
LYXERR(Debug::PAINTING, "Found new anchor pit = " << d->anchor_pit_
<< " anchor ypos = " << d->anchor_ypos_);
d->anchor_pit_ = pit; d->anchor_pit_ = pit;
d->anchor_ypos_ = pm.position(); d->anchor_ypos_ = pm.position();
break; break;
} }
} }
LYXERR(Debug::PAINTING, "Found new anchor pit = " << d->anchor_pit_ if (!pain.isNull()) {
<< " anchor ypos = " << d->anchor_ypos_); // reset the update flags, everything has been done
d->update_flags_ = Update::None;
}
// Remember what has just been done for the next draw() step
if (paint_caret) {
d->caret_slice_ = d->cursor_.top();
if (d->caret_slice_.pos() > 0
&& (d->cursor_.boundary()
|| d->caret_slice_.pos() == d->caret_slice_.lastpos()))
--d->caret_slice_.pos();
} else
d->caret_slice_ = CursorSlice();
} }

View File

@ -42,10 +42,10 @@ class FuncStatus;
class Intl; class Intl;
class Inset; class Inset;
class Length; class Length;
class PainterInfo;
class ParIterator; class ParIterator;
class ParagraphMetrics; class ParagraphMetrics;
class Point; class Point;
class Row;
class TexRow; class TexRow;
class Text; class Text;
class TextMetrics; class TextMetrics;
@ -120,11 +120,12 @@ public:
/// \return true if the BufferView is at the bottom of the document. /// \return true if the BufferView is at the bottom of the document.
bool isBottomScreen() const; bool isBottomScreen() const;
/// perform pending metrics updates. /// Add \p flags to current update flags and trigger an update.
/** \c Update::FitCursor means first to do a FitCursor, and to /* If this method is invoked several times before the update
* actually takes place, the effect is cumulative.
* \c Update::FitCursor means first to do a FitCursor, and to
* force an update if screen position changes. * force an update if screen position changes.
* \c Update::Force means to force an update in any case. * \c Update::Force means to force an update in any case.
* \retval true if a screen redraw is needed
*/ */
void processUpdateFlags(Update::flags flags); void processUpdateFlags(Update::flags flags);
@ -132,6 +133,9 @@ public:
/// Only to be called with good y coordinates (after a bv::metrics) /// Only to be called with good y coordinates (after a bv::metrics)
bool needsFitCursor() const; bool needsFitCursor() const;
/// returns true if this row needs to be repainted (to erase caret)
bool needRepaint(Text const * text, Row const & row) const;
// Returns the amount of horizontal scrolling applied to the // Returns the amount of horizontal scrolling applied to the
// top-level row where the cursor lies // top-level row where the cursor lies
int horizScrollOffset() const; int horizScrollOffset() const;
@ -283,6 +287,10 @@ public:
/// update the internal \c ViewMetricsInfo. /// update the internal \c ViewMetricsInfo.
void updateMetrics(); void updateMetrics();
// this is the "nodraw" drawing stage: only set the positions of the
// insets in metrics cache.
void updatePosCache();
/// ///
TextMetrics const & textMetrics(Text const * t) const; TextMetrics const & textMetrics(Text const * t) const;
TextMetrics & textMetrics(Text const * t); TextMetrics & textMetrics(Text const * t);
@ -300,12 +308,11 @@ public:
bool paragraphVisible(DocIterator const & dit) const; bool paragraphVisible(DocIterator const & dit) const;
/// is the cursor currently visible in the view /// is the cursor currently visible in the view
bool cursorInView(Point const & p, int h) const; bool cursorInView(Point const & p, int h) const;
/// get the position and height of the cursor /// get the position and height of the caret
void cursorPosAndHeight(Point & p, int & h) const; void caretPosAndHeight(Point & p, int & h) const;
/// ///
void draw(frontend::Painter & pain); void draw(frontend::Painter & pain, bool paint_caret);
/// get this view's keyboard map handler. /// get this view's keyboard map handler.
Intl & getIntl(); Intl & getIntl();
@ -361,13 +368,15 @@ private:
/// Update current paragraph metrics. /// Update current paragraph metrics.
/// \return true if no further update is needed. /// \return true if no further update is needed.
bool singleParUpdate(); bool singleParUpdate();
/// do the work for the public updateMetrics()
void updateMetrics(Update::flags & update_flags);
// Set the row on which the cursor lives. // Set the row on which the cursor lives.
void setCurrentRowSlice(CursorSlice const & rowSlice); void setCurrentRowSlice(CursorSlice const & rowSlice);
// Check whether the row where the cursor lives needs to be scrolled. // Check whether the row where the cursor lives needs to be scrolled.
// Update the drawing strategy if needed. // Update the drawing strategy if needed.
void checkCursorScrollOffset(PainterInfo & pi); void checkCursorScrollOffset();
/// The minimal size of the document that is visible. Used /// The minimal size of the document that is visible. Used
/// when it is allowed to scroll below the document. /// when it is allowed to scroll below the document.

View File

@ -136,6 +136,8 @@ void Converter::readFlags()
nice_ = true; nice_ = true;
else if (flag_name == "needauth") else if (flag_name == "needauth")
need_auth_ = true; need_auth_ = true;
else if (flag_name == "hyperref-driver")
href_driver_ = flag_value;
} }
if (!result_dir_.empty() && result_file_.empty()) if (!result_dir_.empty() && result_file_.empty())
result_file_ = "index." + theFormats().extension(to_); result_file_ = "index." + theFormats().extension(to_);
@ -283,6 +285,18 @@ OutputParams::FLAVOR Converters::getFlavor(Graph::EdgePath const & path,
} }
string Converters::getHyperrefDriver(Graph::EdgePath const & path)
{
for (Graph::EdgePath::const_iterator cit = path.begin();
cit != path.end(); ++cit) {
Converter const & conv = converterlist_[*cit];
if (!conv.hyperref_driver().empty())
return conv.hyperref_driver();
}
return string();
}
bool Converters::checkAuth(Converter const & conv, string const & doc_fname, bool Converters::checkAuth(Converter const & conv, string const & doc_fname,
bool use_shell_escape) bool use_shell_escape)
{ {

View File

@ -79,6 +79,8 @@ public:
std::string const result_file() const { return result_file_; } std::string const result_file() const { return result_file_; }
/// ///
std::string const parselog() const { return parselog_; } std::string const parselog() const { return parselog_; }
///
std::string const hyperref_driver() const { return href_driver_; }
private: private:
/// ///
@ -114,6 +116,8 @@ private:
trivstring result_file_; trivstring result_file_;
/// Command to convert the program output to a LaTeX log file format /// Command to convert the program output to a LaTeX log file format
trivstring parselog_; trivstring parselog_;
/// The hyperref driver
trivstring href_driver_;
}; };
@ -159,6 +163,8 @@ public:
/// ///
OutputParams::FLAVOR getFlavor(Graph::EdgePath const & path, OutputParams::FLAVOR getFlavor(Graph::EdgePath const & path,
Buffer const * buffer = 0); Buffer const * buffer = 0);
///
std::string getHyperrefDriver(Graph::EdgePath const & path);
/// Flags for converting files /// Flags for converting files
enum ConversionFlags { enum ConversionFlags {
/// No special flags /// No special flags

View File

@ -453,19 +453,6 @@ int Cursor::currentMode()
} }
bool Cursor::inCoordCache() const
{
// the root inset is not in cache, but we do not need it.
if (depth() == 1)
return true;
CoordCache::Insets const & icache = bv_->coordCache().getInsets();
for (size_t i = 1 ; i < depth() ; ++i)
if (!icache.has(&(*this)[i].inset()))
return false;
return true;
}
void Cursor::getPos(int & x, int & y) const void Cursor::getPos(int & x, int & y) const
{ {
Point p = bv().getPos(*this); Point p = bv().getPos(*this);

View File

@ -215,8 +215,6 @@ public:
/// are we entering a macro name? /// are we entering a macro name?
bool & macromode() { return macromode_; } bool & macromode() { return macromode_; }
/// returns true when all insets in cursor stack are in cache
bool inCoordCache() const;
/// returns x,y position /// returns x,y position
void getPos(int & x, int & y) const; void getPos(int & x, int & y) const;
/// return logical positions between which the cursor is situated /// return logical positions between which the cursor is situated

View File

@ -40,6 +40,7 @@
#include "insets/InsetBibitem.h" #include "insets/InsetBibitem.h"
#include "insets/InsetBranch.h" #include "insets/InsetBranch.h"
#include "insets/InsetCitation.h"
#include "insets/InsetCommand.h" #include "insets/InsetCommand.h"
#include "insets/InsetFlex.h" #include "insets/InsetFlex.h"
#include "insets/InsetGraphics.h" #include "insets/InsetGraphics.h"
@ -360,6 +361,16 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist,
break; break;
} }
case CITE_CODE: {
InsetCitation & cit = static_cast<InsetCitation &>(*it);
// This actually only needs to be done if the cite engine
// differs, but we do it in general.
cit.redoLabel();
// We need to update the list of citations.
need_update = true;
break;
}
case BIBITEM_CODE: { case BIBITEM_CODE: {
// check for duplicates // check for duplicates
InsetBibitem & bib = static_cast<InsetBibitem &>(*it); InsetBibitem & bib = static_cast<InsetBibitem &>(*it);

View File

@ -349,9 +349,11 @@ int Font::latexWriteStartChanges(odocstream & os, BufferParams const & bparams,
// If the current language is Hebrew, Arabic, or Farsi // If the current language is Hebrew, Arabic, or Farsi
// the numbers are written Left-to-Right. ArabTeX package // the numbers are written Left-to-Right. ArabTeX package
// reorders the number automatically but the packages used // and bidi (polyglossia) reorder the number automatically
// for Hebrew and Farsi (Arabi) do not. // but the packages used for Hebrew and Farsi (Arabi) do not.
if (!runparams.pass_thru && bits_.number() == FONT_ON if (!runparams.use_polyglossia
&& !runparams.pass_thru
&& bits_.number() == FONT_ON
&& prev.fontInfo().number() != FONT_ON && prev.fontInfo().number() != FONT_ON
&& (language()->lang() == "hebrew" && (language()->lang() == "hebrew"
|| language()->lang() == "farsi" || language()->lang() == "farsi"
@ -552,9 +554,11 @@ int Font::latexWriteEndChanges(otexstream & os, BufferParams const & bparams,
// If the current language is Hebrew, Arabic, or Farsi // If the current language is Hebrew, Arabic, or Farsi
// the numbers are written Left-to-Right. ArabTeX package // the numbers are written Left-to-Right. ArabTeX package
// reorders the number automatically but the packages used // and bidi (polyglossia) reorder the number automatically
// for Hebrew and Farsi (Arabi) do not. // but the packages used for Hebrew and Farsi (Arabi) do not.
if (!runparams.pass_thru && bits_.number() == FONT_ON if (!runparams.use_polyglossia
&& !runparams.pass_thru
&& bits_.number() == FONT_ON
&& next.fontInfo().number() != FONT_ON && next.fontInfo().number() != FONT_ON
&& (language()->lang() == "hebrew" && (language()->lang() == "hebrew"
|| language()->lang() == "farsi" || language()->lang() == "farsi"

View File

@ -474,6 +474,10 @@ enum FuncCode
LFUN_TOOLBAR_MOVABLE, // daniel, 20160712 LFUN_TOOLBAR_MOVABLE, // daniel, 20160712
LFUN_FONT_CROSSOUT, // uwestoehr 20170404 LFUN_FONT_CROSSOUT, // uwestoehr 20170404
LFUN_DEVEL_MODE_TOGGLE, // lasgouttes 20170723 LFUN_DEVEL_MODE_TOGGLE, // lasgouttes 20170723
//370
LFUN_EXPORT_CANCEL, // rgh, 20171227
LFUN_BUFFER_ANONYMIZE, // sanda, 20180201
LFUN_GRAPHICS_UNIFY, // sanda, 20180207
LFUN_LASTACTION // end of the table LFUN_LASTACTION // end of the table
}; };

View File

@ -356,7 +356,11 @@ SpellChecker::Result HunspellChecker::check(WordLangTuple const & wl)
LYXERR(Debug::GUI, "spellCheck: \"" << LYXERR(Debug::GUI, "spellCheck: \"" <<
wl.word() << "\", lang = " << wl.lang()->lang()) ; wl.word() << "\", lang = " << wl.lang()->lang()) ;
#ifdef HAVE_HUNSPELL_CXXABI
if (h->spell(word_to_check, &info))
#else
if (h->spell(word_to_check.c_str(), &info)) if (h->spell(word_to_check.c_str(), &info))
#endif
return d->learned(wl) ? LEARNED_WORD : WORD_OK; return d->learned(wl) ? LEARNED_WORD : WORD_OK;
if (info & SPELL_COMPOUND) { if (info & SPELL_COMPOUND) {
@ -411,6 +415,11 @@ void HunspellChecker::suggest(WordLangTuple const & wl,
return; return;
string const encoding = h->get_dic_encoding(); string const encoding = h->get_dic_encoding();
string const word_to_check = to_iconv_encoding(wl.word(), encoding); string const word_to_check = to_iconv_encoding(wl.word(), encoding);
#ifdef HAVE_HUNSPELL_CXXABI
vector<string> wlst = h->suggest(word_to_check);
for (auto const s : wlst)
suggestions.push_back(from_iconv_encoding(s, encoding));
#else
char ** suggestion_list; char ** suggestion_list;
int const suggestion_number = h->suggest(&suggestion_list, word_to_check.c_str()); int const suggestion_number = h->suggest(&suggestion_list, word_to_check.c_str());
if (suggestion_number <= 0) if (suggestion_number <= 0)
@ -418,6 +427,7 @@ void HunspellChecker::suggest(WordLangTuple const & wl,
for (int i = 0; i != suggestion_number; ++i) for (int i = 0; i != suggestion_number; ++i)
suggestions.push_back(from_iconv_encoding(suggestion_list[i], encoding)); suggestions.push_back(from_iconv_encoding(suggestion_list[i], encoding));
h->free_list(&suggestion_list, suggestion_number); h->free_list(&suggestion_list, suggestion_number);
#endif
} }
@ -430,6 +440,11 @@ void HunspellChecker::stem(WordLangTuple const & wl,
return; return;
string const encoding = h->get_dic_encoding(); string const encoding = h->get_dic_encoding();
string const word_to_check = to_iconv_encoding(wl.word(), encoding); string const word_to_check = to_iconv_encoding(wl.word(), encoding);
#ifdef HAVE_HUNSPELL_CXXABI
vector<string> wlst = h->stem(word_to_check);
for (auto const s : wlst)
suggestions.push_back(from_iconv_encoding(s, encoding));
#else
char ** suggestion_list; char ** suggestion_list;
int const suggestion_number = h->stem(&suggestion_list, word_to_check.c_str()); int const suggestion_number = h->stem(&suggestion_list, word_to_check.c_str());
if (suggestion_number <= 0) if (suggestion_number <= 0)
@ -437,6 +452,7 @@ void HunspellChecker::stem(WordLangTuple const & wl,
for (int i = 0; i != suggestion_number; ++i) for (int i = 0; i != suggestion_number; ++i)
suggestions.push_back(from_iconv_encoding(suggestion_list[i], encoding)); suggestions.push_back(from_iconv_encoding(suggestion_list[i], encoding));
h->free_list(&suggestion_list, suggestion_number); h->free_list(&suggestion_list, suggestion_number);
#endif
} }

View File

@ -120,7 +120,7 @@ enum LayoutTags {
///////////////////// /////////////////////
Layout::Layout() Layout::Layout()
: add_to_toc_(false), is_toc_caption_(false) : add_to_toc_(false), is_toc_caption_(true)
{ {
unknown_ = false; unknown_ = false;
margintype = MARGIN_STATIC; margintype = MARGIN_STATIC;

View File

@ -1950,8 +1950,10 @@ void LyXAction::init()
/*! /*!
* \var lyx::FuncCode lyx::LFUN_INSET_BEGIN * \var lyx::FuncCode lyx::LFUN_INSET_BEGIN
* \li Action: Move the cursor to the beginning of the current inset * \li Action: Move the cursor to the beginning of the current inset
if it is not already there, or at the beginning of the if it is not already there. If the cursor is already at
enclosing inset otherwise the beginning of the current inset, move it to the
beginning of the enclosing inset or the main work area,
respectively, if there is no enclosing inset.
* \li Syntax: inset-begin * \li Syntax: inset-begin
* \li Origin: lasgouttes, 16 Mar 2009 * \li Origin: lasgouttes, 16 Mar 2009
* \endvar * \endvar
@ -1961,8 +1963,10 @@ void LyXAction::init()
/*! /*!
* \var lyx::FuncCode lyx::LFUN_INSET_BEGIN_SELECT * \var lyx::FuncCode lyx::LFUN_INSET_BEGIN_SELECT
* \li Action: Move the cursor to the beginning of the current inset * \li Action: Move the cursor to the beginning of the current inset
if it is not already there, or at the beginning of the if it is not already there. If the cursor is already at
enclosing inset otherwise (adding the the beginning of the current inset, move it to the
beginning of the enclosing inset or the main work area,
respectively, if there is no enclosing inset (adding the
traversed text to the selection). traversed text to the selection).
* \li Syntax: inset-begin-select * \li Syntax: inset-begin-select
* \li Origin: lasgouttes, 16 Mar 2009 * \li Origin: lasgouttes, 16 Mar 2009
@ -2021,9 +2025,11 @@ void LyXAction::init()
/*! /*!
* \var lyx::FuncCode lyx::LFUN_INSET_END * \var lyx::FuncCode lyx::LFUN_INSET_END
* \li Action: Move the cursor to the end of the current inset * \li Action: Move the cursor to the end of the current inset if it
if it is not already there, or at the end of the is not already there. If the cursor is already at the
enclosing inset otherwise end of the current inset, move it to the end of the
enclosing inset or the main work area, respectively, if
there is no enclosing inset.
* \li Syntax: inset-end * \li Syntax: inset-end
* \li Origin: lasgouttes, 16 Mar 2009 * \li Origin: lasgouttes, 16 Mar 2009
* \endvar * \endvar
@ -2032,9 +2038,11 @@ void LyXAction::init()
/*! /*!
* \var lyx::FuncCode lyx::LFUN_INSET_END_SELECT * \var lyx::FuncCode lyx::LFUN_INSET_END_SELECT
* \li Action: Move the cursor to the end of the current inset * \li Action: Move the cursor to the end of the current inset if it
if it is not already there, or at the end of the is not already there. If the cursor is already at the
enclosing inset otherwise (adding the end of the current inset, move it to the end of the
enclosing inset or the main work area, respectively, if
there is no enclosing inset (adding the
traversed text to the selection). traversed text to the selection).
* \li Syntax: inset-end-select * \li Syntax: inset-end-select
* \li Origin: lasgouttes, 16 Mar 2009 * \li Origin: lasgouttes, 16 Mar 2009
@ -3545,6 +3553,17 @@ void LyXAction::init()
*/ */
{ LFUN_SET_GRAPHICS_GROUP, "set-graphics-group", Noop, Edit }, { LFUN_SET_GRAPHICS_GROUP, "set-graphics-group", Noop, Edit },
/*!
* \var lyx::FuncCode lyx::LFUN_GRAPHICS_UNIFY
* \li Action: Set the same group for all graphics insets in the marked block.
* \li Syntax: graphics-unify [<GROUP>]
* \li Params: <GROUP>: Id for an existing group. In case the Id is an empty string,
the group Id from the first graphics inset will be used.
* \li Origin: sanda, 7 Feb 2018
* \endvar
*/
{ LFUN_GRAPHICS_UNIFY, "graphics-unify", Noop, Edit },
/*! /*!
* \var lyx::FuncCode lyx::LFUN_SPACE_INSERT * \var lyx::FuncCode lyx::LFUN_SPACE_INSERT
@ -4209,6 +4228,16 @@ void LyXAction::init()
*/ */
{ LFUN_WORD_REPLACE, "word-replace", Noop, Edit }, { LFUN_WORD_REPLACE, "word-replace", Noop, Edit },
/*!
* \var lyx::FuncCode lyx::LFUN_BUFFER_ANONYMIZE
* \li Action: For debug purposes only. Convert all [a-zA-Z0-1] characters to
single character. Useful when submitting docs to list or bugzilla.
* \li Syntax: buffer-anonymize
* \li Origin: sanda, Feb 1 2018
* \endvar
*/
{ LFUN_BUFFER_ANONYMIZE, "buffer-anonymize", Noop, Edit },
/*! /*!
* \var lyx::FuncCode lyx::LFUN_WORD_RIGHT * \var lyx::FuncCode lyx::LFUN_WORD_RIGHT
* \li Action: Moves the cursor to the next beginning of a word "on the right". * \li Action: Moves the cursor to the next beginning of a word "on the right".

View File

@ -195,6 +195,7 @@ LexerKeyword lyxrcTags[] = {
{ "\\use_converter_needauth", LyXRC::RC_USE_CONVERTER_NEEDAUTH }, { "\\use_converter_needauth", LyXRC::RC_USE_CONVERTER_NEEDAUTH },
{ "\\use_converter_needauth_forbidden", LyXRC::RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN }, { "\\use_converter_needauth_forbidden", LyXRC::RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN },
{ "\\use_lastfilepos", LyXRC::RC_USELASTFILEPOS }, { "\\use_lastfilepos", LyXRC::RC_USELASTFILEPOS },
{ "\\use_native_filedialog", LyXRC::RC_USE_NATIVE_FILEDIALOG },
{ "\\use_pixmap_cache", LyXRC::RC_USE_PIXMAP_CACHE }, { "\\use_pixmap_cache", LyXRC::RC_USE_PIXMAP_CACHE },
{ "\\use_qimage", LyXRC::RC_USE_QIMAGE }, { "\\use_qimage", LyXRC::RC_USE_QIMAGE },
// compatibility with versions older than 1.4.0 only // compatibility with versions older than 1.4.0 only
@ -273,6 +274,7 @@ void LyXRC::setDefaults()
num_lastfiles = 20; num_lastfiles = 20;
check_lastfiles = true; check_lastfiles = true;
use_lastfilepos = true; use_lastfilepos = true;
use_native_filedialog = true;
load_session = false; load_session = false;
make_backup = true; make_backup = true;
save_compressed = false; save_compressed = false;
@ -875,6 +877,9 @@ LyXRC::ReturnValues LyXRC::read(Lexer & lexrc, bool check_format)
case RC_ACCEPT_COMPOUND: case RC_ACCEPT_COMPOUND:
lexrc >> spellchecker_accept_compound; lexrc >> spellchecker_accept_compound;
break; break;
case RC_USE_NATIVE_FILEDIALOG:
lexrc >> use_native_filedialog;
break;
case RC_USE_SYSTEM_COLORS: case RC_USE_SYSTEM_COLORS:
lexrc >> use_system_colors; lexrc >> use_system_colors;
break; break;
@ -2412,6 +2417,16 @@ void LyXRC::write(ostream & os, bool ignore_system_lyxrc, string const & name) c
if (tag != RC_LAST) if (tag != RC_LAST)
break; break;
// fall through // fall through
case RC_USE_NATIVE_FILEDIALOG:
if (ignore_system_lyxrc ||
use_native_filedialog != system_lyxrc.use_native_filedialog) {
os << "\\use_native_filedialog "
<< convert<string>(use_native_filedialog)
<< '\n';
}
if (tag != RC_LAST)
break;
// fall through
case RC_USE_SYSTEM_COLORS: case RC_USE_SYSTEM_COLORS:
if (ignore_system_lyxrc || if (ignore_system_lyxrc ||
use_system_colors != system_lyxrc.use_system_colors) { use_system_colors != system_lyxrc.use_system_colors) {
@ -3031,6 +3046,7 @@ void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
case LyXRC::RC_USE_CONVERTER_CACHE: case LyXRC::RC_USE_CONVERTER_CACHE:
case LyXRC::RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN: case LyXRC::RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN:
case LyXRC::RC_USE_CONVERTER_NEEDAUTH: case LyXRC::RC_USE_CONVERTER_NEEDAUTH:
case LyXRC::RC_USE_NATIVE_FILEDIALOG:
case LyXRC::RC_USE_SYSTEM_COLORS: case LyXRC::RC_USE_SYSTEM_COLORS:
case LyXRC::RC_USE_TOOLTIP: case LyXRC::RC_USE_TOOLTIP:
case LyXRC::RC_USE_PIXMAP_CACHE: case LyXRC::RC_USE_PIXMAP_CACHE:

View File

@ -172,6 +172,7 @@ public:
RC_USE_CONVERTER_CACHE, RC_USE_CONVERTER_CACHE,
RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN, RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN,
RC_USE_CONVERTER_NEEDAUTH, RC_USE_CONVERTER_NEEDAUTH,
RC_USE_NATIVE_FILEDIALOG,
RC_USE_SYSTEM_COLORS, RC_USE_SYSTEM_COLORS,
RC_USE_TOOLTIP, RC_USE_TOOLTIP,
RC_USE_PIXMAP_CACHE, RC_USE_PIXMAP_CACHE,
@ -333,6 +334,8 @@ public:
bool use_tooltip; bool use_tooltip;
/// Use the colors from current system theme? /// Use the colors from current system theme?
bool use_system_colors; bool use_system_colors;
/// use native file dialog or our own ?
bool use_native_filedialog;
/// Use pixmap cache? /// Use pixmap cache?
bool use_pixmap_cache; bool use_pixmap_cache;
/// Use QImage backend? /// Use QImage backend?

View File

@ -130,7 +130,7 @@ public:
bool selected; bool selected;
/// Whether the spell checker is enabled for the parent /// Whether the spell checker is enabled for the parent
bool do_spellcheck; bool do_spellcheck;
/// /// True when it can be assumed that the screen has been cleared
bool full_repaint; bool full_repaint;
/// Current background color /// Current background color
ColorCode background_color; ColorCode background_color;

View File

@ -172,6 +172,10 @@ public:
*/ */
std::string index_command; std::string index_command;
/** Hyperref driver
*/
std::string hyperref_driver;
/** Line length to use with plaintext or LaTeX export. /** Line length to use with plaintext or LaTeX export.
*/ */
size_type linelen; size_type linelen;

View File

@ -97,6 +97,10 @@ void PDFOptions::writeLaTeX(OutputParams & runparams, otexstream & os,
string opt; string opt;
string hyperset; string hyperset;
// Driver needed by specific converters
if (!runparams.hyperref_driver.empty())
opt += runparams.hyperref_driver + ",";
// since LyX uses unicode, also set the PDF strings to unicode strings with the // since LyX uses unicode, also set the PDF strings to unicode strings with the
// hyperref option "unicode" // hyperref option "unicode"
opt += "unicode=true,"; opt += "unicode=true,";

View File

@ -1437,43 +1437,18 @@ bool Paragraph::Private::latexSpecialT3(char_type const c, otexstream & os,
void Paragraph::Private::validate(LaTeXFeatures & features) const void Paragraph::Private::validate(LaTeXFeatures & features) const
{ {
if (layout_->inpreamble && inset_owner_) { if (layout_->inpreamble && inset_owner_) {
bool const is_command = layout_->latextype == LATEX_COMMAND; // FIXME: Using a string stream here circumvents the encoding
Font f;
// Using a string stream here circumvents the encoding
// switching machinery of odocstream. Therefore the // switching machinery of odocstream. Therefore the
// output is wrong if this paragraph contains content // output is wrong if this paragraph contains content
// that needs to switch encoding. // that needs to switch encoding.
Buffer const & buf = inset_owner_->buffer(); Buffer const & buf = inset_owner_->buffer();
BufferParams const & bp = features.runparams().is_child
? buf.masterParams() : buf.params();
otexstringstream os; otexstringstream os;
os << layout_->preamble(); os << layout_->preamble();
if (is_command) {
os << '\\' << from_ascii(layout_->latexname());
// we have to provide all the optional arguments here, even though
// the last one is the only one we care about.
// Separate handling of optional argument inset.
if (!layout_->latexargs().empty()) {
OutputParams rp = features.runparams();
rp.local_font = &owner_->getFirstFontSettings(bp);
latexArgInsets(*owner_, os, rp, layout_->latexargs());
}
os << from_ascii(layout_->latexparam());
}
size_t const length = os.length(); size_t const length = os.length();
// this will output "{" at the beginning, but not at the end TeXOnePar(buf, buf.text(), buf.getParFromID(owner_->id()).pit(), os,
owner_->latex(bp, f, os, features.runparams(), 0, -1, true); features.runparams(), string(), 0, -1, true);
if (os.length() > length) { if (os.length() > length)
if (is_command) {
os << '}';
if (!layout_->postcommandargs().empty()) {
OutputParams rp = features.runparams();
rp.local_font = &owner_->getFirstFontSettings(bp);
latexArgInsets(*owner_, os, rp, layout_->postcommandargs(), "post:");
}
}
features.addPreambleSnippet(os.release(), true); features.addPreambleSnippet(os.release(), true);
}
} }
if (features.runparams().flavor == OutputParams::HTML if (features.runparams().flavor == OutputParams::HTML
@ -2426,7 +2401,9 @@ void Paragraph::latex(BufferParams const & bparams,
// if the paragraph is empty, the loop will not be entered at all // if the paragraph is empty, the loop will not be entered at all
if (empty()) { if (empty()) {
if (style.isCommand()) { // For InTitle commands, we have already opened a group
// in output_latex::TeXOnePar.
if (style.isCommand() && !style.intitle) {
os << '{'; os << '{';
++column; ++column;
} }
@ -2464,7 +2441,9 @@ void Paragraph::latex(BufferParams const & bparams,
os << "}] "; os << "}] ";
column +=3; column +=3;
} }
if (style.isCommand()) { // For InTitle commands, we have already opened a group
// in output_latex::TeXOnePar.
if (style.isCommand() && !style.intitle) {
os << '{'; os << '{';
++column; ++column;
} }
@ -3531,6 +3510,8 @@ void Paragraph::forOutliner(docstring & os, size_t const maxlen,
size_t tmplen = shorten ? maxlen + 1 : maxlen; size_t tmplen = shorten ? maxlen + 1 : maxlen;
if (label && !labelString().empty()) if (label && !labelString().empty())
os += labelString() + ' '; os += labelString() + ' ';
if (!layout().isTocCaption())
return;
for (pos_type i = 0; i < size() && os.length() < tmplen; ++i) { for (pos_type i = 0; i < size() && os.length() < tmplen; ++i) {
if (isDeleted(i)) if (isDeleted(i))
continue; continue;
@ -4176,6 +4157,15 @@ SpellChecker::Result Paragraph::spellCheck(pos_type & from, pos_type & to,
} }
void Paragraph::anonymize()
{
// This is a very crude anonymization for now
for (char_type & c : d->text_)
if (isLetterChar(c) || isNumber(c))
c = 'a';
}
void Paragraph::Private::markMisspelledWords( void Paragraph::Private::markMisspelledWords(
pos_type const & first, pos_type const & last, pos_type const & first, pos_type const & last,
SpellChecker::Result result, SpellChecker::Result result,

View File

@ -505,6 +505,10 @@ public:
/// presently used only in the XHTML output routines. /// presently used only in the XHTML output routines.
std::string magicLabel() const; std::string magicLabel() const;
/// anonymizes the paragraph contents (but not the paragraphs
/// contained inside it. Does not handle undo.
void anonymize();
private: private:
/// Expand the counters for the labelstring of \c layout /// Expand the counters for the labelstring of \c layout
docstring expandParagraphLabel(Layout const &, BufferParams const &, docstring expandParagraphLabel(Layout const &, BufferParams const &,

View File

@ -47,8 +47,6 @@
#include "support/lstrings.h" #include "support/lstrings.h"
#include "support/textutils.h" #include "support/textutils.h"
#include <boost/crc.hpp>
#include <algorithm> #include <algorithm>
#include <list> #include <list>
#include <stack> #include <stack>
@ -84,42 +82,6 @@ void ParagraphMetrics::reset(Paragraph const & par)
} }
size_t ParagraphMetrics::computeRowSignature(Row const & row,
BufferView const & bv) const
{
boost::crc_32_type crc;
for (pos_type i = row.pos(); i < row.endpos(); ++i) {
if (par_->isInset(i)) {
Inset const * in = par_->getInset(i);
Dimension const d = in->dimension(bv);
int const b[] = { d.wid, d.asc, d.des };
crc.process_bytes(b, sizeof(b));
} else {
char_type const b[] = { par_->getChar(i) };
crc.process_bytes(b, sizeof(char_type));
}
if (bv.buffer().params().track_changes) {
Change change = par_->lookupChange(i);
char_type const b[] = { static_cast<char_type>(change.type) };
// 1 byte is enough to encode Change::Type
crc.process_bytes(b, 1);
}
}
pos_type const b1[] = { row.sel_beg, row.sel_end };
crc.process_bytes(b1, sizeof(b1));
Dimension const & d = row.dimension();
int const b2[] = { row.begin_margin_sel,
row.end_margin_sel,
d.wid, d.asc, d.des };
crc.process_bytes(b2, sizeof(b2));
crc.process_bytes(&row.separator, sizeof(row.separator));
return crc.checksum();
}
void ParagraphMetrics::setPosition(int position) void ParagraphMetrics::setPosition(int position)
{ {
position_ = position; position_ = position;

View File

@ -85,9 +85,6 @@ public:
/// ///
bool hfillExpansion(Row const & row, pos_type pos) const; bool hfillExpansion(Row const & row, pos_type pos) const;
///
size_t computeRowSignature(Row const &, BufferView const & bv) const;
/// ///
int position() const { return position_; } int position() const { return position_; }
void setPosition(int position); void setPosition(int position);

View File

@ -162,19 +162,13 @@ Row::Row()
: separator(0), label_hfill(0), left_margin(0), right_margin(0), : separator(0), label_hfill(0), left_margin(0), right_margin(0),
sel_beg(-1), sel_end(-1), sel_beg(-1), sel_end(-1),
begin_margin_sel(false), end_margin_sel(false), begin_margin_sel(false), end_margin_sel(false),
changed_(false), crc_(0), changed_(true),
pit_(0), pos_(0), end_(0), pit_(0), pos_(0), end_(0),
right_boundary_(false), flushed_(false), rtl_(false) right_boundary_(false), flushed_(false), rtl_(false),
changebar_(false)
{} {}
void Row::setCrc(size_type crc) const
{
changed_ = crc != crc_;
crc_ = crc;
}
bool Row::isMarginSelected(bool left_margin, DocIterator const & beg, bool Row::isMarginSelected(bool left_margin, DocIterator const & beg,
DocIterator const & end) const DocIterator const & end) const
{ {
@ -209,8 +203,8 @@ void Row::setSelectionAndMargins(DocIterator const & beg,
setSelection(beg.pos(), end.pos()); setSelection(beg.pos(), end.pos());
if (selection()) { if (selection()) {
end_margin_sel = isMarginSelected(false, beg, end); change(end_margin_sel, isMarginSelected(false, beg, end));
begin_margin_sel = isMarginSelected(true, beg, end); change(begin_margin_sel, isMarginSelected(true, beg, end));
} }
} }
@ -218,18 +212,18 @@ void Row::setSelectionAndMargins(DocIterator const & beg,
void Row::setSelection(pos_type beg, pos_type end) const void Row::setSelection(pos_type beg, pos_type end) const
{ {
if (pos_ >= beg && pos_ <= end) if (pos_ >= beg && pos_ <= end)
sel_beg = pos_; change(sel_beg, pos_);
else if (beg > pos_ && beg <= end_) else if (beg > pos_ && beg <= end_)
sel_beg = beg; change(sel_beg, beg);
else else
sel_beg = -1; change(sel_beg, -1);
if (end_ >= beg && end_ <= end) if (end_ >= beg && end_ <= end)
sel_end = end_; change(sel_end,end_);
else if (end < end_ && end >= pos_) else if (end < end_ && end >= pos_)
sel_end = end; change(sel_end, end);
else else
sel_end = -1; change(sel_end, -1);
} }
@ -371,6 +365,8 @@ void Row::finalizeLast()
if (elt.final) if (elt.final)
return; return;
elt.final = true; elt.final = true;
if (elt.change.changed())
changebar_ = true;
if (elt.type == STRING) { if (elt.type == STRING) {
dim_.wid -= elt.dim.wid; dim_.wid -= elt.dim.wid;

View File

@ -136,12 +136,33 @@ public:
/// ///
Row(); Row();
/**
* Helper function: set variable \c var to value \c val, and mark
* row as changed is the values were different. This is intended
* for use when changing members of the row object.
*/
template<class T1, class T2>
void change(T1 & var, T2 const val) {
if (var != val)
changed(true);
var = val;
}
/**
* Helper function: set variable \c var to value \c val, and mark
* row as changed is the values were different. This is intended
* for use when changing members of the row object.
* This is the const version, useful for mutable members.
*/
template<class T1, class T2>
void change(T1 & var, T2 const val) const {
if (var != val)
changed(true);
var = val;
}
/// ///
bool changed() const { return changed_; } bool changed() const { return changed_; }
/// ///
void setChanged(bool c) { changed_ = c; } void changed(bool c) const { changed_ = c; }
///
void setCrc(size_type crc) const;
/// Set the selection begin and end. /// Set the selection begin and end.
/** /**
* This is const because we update the selection status only at draw() * This is const because we update the selection status only at draw()
@ -266,6 +287,11 @@ public:
void reverseRTL(bool rtl_par); void reverseRTL(bool rtl_par);
/// ///
bool isRTL() const { return rtl_; } bool isRTL() const { return rtl_; }
///
bool needsChangeBar() const { return changebar_; }
///
void needsChangeBar(bool ncb) { changebar_ = ncb; }
/// Find row element that contains \c pos, and compute x offset. /// Find row element that contains \c pos, and compute x offset.
const_iterator const findElement(pos_type pos, bool boundary, double & x) const; const_iterator const findElement(pos_type pos, bool boundary, double & x) const;
@ -310,8 +336,6 @@ private:
/// has the Row appearance changed since last drawing? /// has the Row appearance changed since last drawing?
mutable bool changed_; mutable bool changed_;
/// CRC of row contents.
mutable size_type crc_;
/// Index of the paragraph that contains this row /// Index of the paragraph that contains this row
pit_type pit_; pit_type pit_;
/// first pos covered by this row /// first pos covered by this row
@ -326,6 +350,8 @@ private:
Dimension dim_; Dimension dim_;
/// true when this row lives in a right-to-left paragraph /// true when this row lives in a right-to-left paragraph
bool rtl_; bool rtl_;
/// true when a changebar should be drawn in the margin
bool changebar_;
}; };

View File

@ -247,18 +247,6 @@ void RowPainter::paintChange(Row::Element const & e) const
void RowPainter::paintChangeBar() const void RowPainter::paintChangeBar() const
{ {
pos_type const start = row_.pos();
pos_type end = row_.endpos();
if (par_.size() == end) {
// this is the last row of the paragraph;
// thus, we must also consider the imaginary end-of-par character
end++;
}
if (start == end || !par_.isChanged(start, end))
return;
int const height = tm_.isLastRow(row_) int const height = tm_.isLastRow(row_)
? row_.ascent() ? row_.ascent()
: row_.height(); : row_.height();
@ -576,7 +564,7 @@ void RowPainter::paintText()
paintStringAndSel(e); paintStringAndSel(e);
// Paint the spelling marks if enabled. // Paint the spelling marks if enabled.
if (lyxrc.spellcheck_continuously && pi_.do_spellcheck && pi_.pain.isDrawingEnabled()) if (lyxrc.spellcheck_continuously && pi_.do_spellcheck && !pi_.pain.isNull())
paintMisspelledMark(e); paintMisspelledMark(e);
break; break;

View File

@ -99,6 +99,18 @@ string envName(Spacing::Space space, bool useSetSpace)
return useSetSpace ? name : support::ascii_lowercase(name); return useSetSpace ? name : support::ascii_lowercase(name);
} }
string cmdName(Spacing::Space space, bool useSetSpace)
{
static char const * const cmd_names[]
= { "SingleSpacing", "OnehalfSpacing", "DoubleSpacing", "SetStretch", ""};
string const name = cmd_names[space];
if (useSetSpace && name == "SetStretch")
return "setSpacing";
return useSetSpace ? name : support::ascii_lowercase(name);
}
} // namespace } // namespace
string const Spacing::writeEnvirBegin(bool useSetSpace) const string const Spacing::writeEnvirBegin(bool useSetSpace) const
@ -118,6 +130,16 @@ string const Spacing::writeEnvirEnd(bool useSetSpace) const
} }
string const Spacing::writeCmd(bool useSetSpace) const
{
string const name = cmdName(space, useSetSpace);
if (space == Other)
return "\\" + name + "{" + getValueAsString() + '}';
else
return name.empty() ? string() : "\\" + name + "{}";
}
string const Spacing::writePreamble(bool useSetSpace) const string const Spacing::writePreamble(bool useSetSpace) const
{ {
string preamble; string preamble;

View File

@ -62,6 +62,9 @@ public:
std::string const writeEnvirEnd(bool useSetSpace) const; std::string const writeEnvirEnd(bool useSetSpace) const;
/// useSetSpace is true when using the variant supported by /// useSetSpace is true when using the variant supported by
/// the memoir class. /// the memoir class.
std::string const writeCmd(bool useSetSpace) const;
/// useSetSpace is true when using the variant supported by
/// the memoir class.
std::string const writePreamble(bool useSetSpace) const; std::string const writePreamble(bool useSetSpace) const;
private: private:

View File

@ -1977,7 +1977,7 @@ docstring Text::getPossibleLabel(Cursor const & cur) const
Layout const * layout = &(pars_[pit].layout()); Layout const * layout = &(pars_[pit].layout());
docstring text; docstring text;
docstring par_text = pars_[pit].asString(); docstring par_text = pars_[pit].asString(AS_STR_SKIPDELETE);
// The return string of math matrices might contain linebreaks // The return string of math matrices might contain linebreaks
par_text = subst(par_text, '\n', '-'); par_text = subst(par_text, '\n', '-');

View File

@ -860,6 +860,18 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
cur.upDownInText(up, needsUpdate); cur.upDownInText(up, needsUpdate);
needsUpdate |= cur.beforeDispatchCursor().inMathed(); needsUpdate |= cur.beforeDispatchCursor().inMathed();
} else { } else {
pos_type newpos = up ? 0 : cur.lastpos();
if (lyxrc.mac_like_cursor_movement && cur.pos() != newpos) {
needsUpdate |= cur.selHandle(select);
// we do not reset the targetx of the cursor
cur.pos() = newpos;
needsUpdate |= bv->checkDepm(cur, bv->cursor());
cur.updateTextTargetOffset();
if (needsUpdate)
cur.forceBufferUpdate();
break;
}
// if the cursor cannot be moved up or down do not remove // if the cursor cannot be moved up or down do not remove
// the selection right now, but wait for the next dispatch. // the selection right now, but wait for the next dispatch.
if (select) if (select)

View File

@ -43,7 +43,9 @@
#include "frontends/FontMetrics.h" #include "frontends/FontMetrics.h"
#include "frontends/Painter.h" #include "frontends/Painter.h"
#include "frontends/NullPainter.h"
#include "support/convert.h"
#include "support/debug.h" #include "support/debug.h"
#include "support/lassert.h" #include "support/lassert.h"
@ -198,6 +200,14 @@ bool TextMetrics::metrics(MetricsInfo & mi, Dimension & dim, int min_width)
} }
void TextMetrics::updatePosCache(pit_type pit) const
{
frontend::NullPainter np;
PainterInfo pi(bv_, np);
drawParagraph(pi, pit, origin_.x_, par_metrics_[pit].position());
}
int TextMetrics::rightMargin(ParagraphMetrics const & pm) const int TextMetrics::rightMargin(ParagraphMetrics const & pm) const
{ {
return text_->isMainText() ? pm.rightMargin(*bv_) : 0; return text_->isMainText() ? pm.rightMargin(*bv_) : 0;
@ -459,7 +469,7 @@ bool TextMetrics::redoParagraph(pit_type const pit)
row.pit(pit); row.pit(pit);
need_new_row = breakRow(row, right_margin); need_new_row = breakRow(row, right_margin);
setRowHeight(row); setRowHeight(row);
row.setChanged(false); row.changed(true);
if (row_index || row.endpos() < par.size() if (row_index || row.endpos() < par.size()
|| (row.right_boundary() && par.inInset().lyxCode() != CELL_CODE)) { || (row.right_boundary() && par.inInset().lyxCode() != CELL_CODE)) {
/* If there is more than one row or the row has been /* If there is more than one row or the row has been
@ -955,6 +965,10 @@ bool TextMetrics::breakRow(Row & row, int const right_margin) const
row.addVirtual(end, docstring(1, char_type(0x00B6)), f, Change()); row.addVirtual(end, docstring(1, char_type(0x00B6)), f, Change());
} }
// Is there a end-of-paragaph change?
if (i == end && par.lookupChange(end).changed() && !need_new_row)
row.needsChangeBar(true);
// if the row is too large, try to cut at last separator. In case // if the row is too large, try to cut at last separator. In case
// of success, reset indication that the row was broken abruptly. // of success, reset indication that the row was broken abruptly.
int const next_width = max_width_ - leftMargin(row.pit(), row.endpos()) int const next_width = max_width_ - leftMargin(row.pit(), row.endpos())
@ -1214,6 +1228,7 @@ void TextMetrics::newParMetricsDown()
redoParagraph(pit); redoParagraph(pit);
par_metrics_[pit].setPosition(last.second.position() par_metrics_[pit].setPosition(last.second.position()
+ last.second.descent() + par_metrics_[pit].ascent()); + last.second.descent() + par_metrics_[pit].ascent());
updatePosCache(pit);
} }
@ -1228,6 +1243,7 @@ void TextMetrics::newParMetricsUp()
redoParagraph(pit); redoParagraph(pit);
par_metrics_[pit].setPosition(first.second.position() par_metrics_[pit].setPosition(first.second.position()
- first.second.ascent() - par_metrics_[pit].descent()); - first.second.ascent() - par_metrics_[pit].descent());
updatePosCache(pit);
} }
// y is screen coordinate // y is screen coordinate
@ -1486,14 +1502,14 @@ int TextMetrics::cursorX(CursorSlice const & sl,
int TextMetrics::cursorY(CursorSlice const & sl, bool boundary) const int TextMetrics::cursorY(CursorSlice const & sl, bool boundary) const
{ {
//lyxerr << "TextMetrics::cursorY: boundary: " << boundary << endl; //lyxerr << "TextMetrics::cursorY: boundary: " << boundary << endl;
ParagraphMetrics const & pm = par_metrics_[sl.pit()]; ParagraphMetrics const & pm = parMetrics(sl.pit());
if (pm.rows().empty()) if (pm.rows().empty())
return 0; return 0;
int h = 0; int h = 0;
h -= par_metrics_[0].rows()[0].ascent(); h -= parMetrics(0).rows()[0].ascent();
for (pit_type pit = 0; pit < sl.pit(); ++pit) { for (pit_type pit = 0; pit < sl.pit(); ++pit) {
h += par_metrics_[pit].height(); h += parMetrics(pit).height();
} }
int pos = sl.pos(); int pos = sl.pos();
if (pos && boundary) if (pos && boundary)
@ -1797,8 +1813,8 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
return; return;
size_t const nrows = pm.rows().size(); size_t const nrows = pm.rows().size();
// Use fast lane when drawing is disabled. // Use fast lane in nodraw stage.
if (!pi.pain.isDrawingEnabled()) { if (pi.pain.isNull()) {
for (size_t i = 0; i != nrows; ++i) { for (size_t i = 0; i != nrows; ++i) {
Row const & row = pm.rows()[i]; Row const & row = pm.rows()[i];
@ -1850,17 +1866,11 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
if (i) if (i)
y += row.ascent(); y += row.ascent();
RowPainter rp(pi, *text_, row, row_x, y);
// It is not needed to draw on screen if we are not inside. // It is not needed to draw on screen if we are not inside.
bool const inside = (y + row.descent() >= 0 bool const inside = (y + row.descent() >= 0
&& y - row.ascent() < ww); && y - row.ascent() < ww);
pi.pain.setDrawingEnabled(inside);
if (!inside) { if (!inside) {
// Paint only the insets to set inset cache correctly // Inset positions have already been set in nodraw stage.
// FIXME: remove paintOnlyInsets when we know that positions
// have already been set.
rp.paintOnlyInsets();
y += row.descent(); y += row.descent();
continue; continue;
} }
@ -1874,27 +1884,30 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
// whether this row is the first or last and update the margins. // whether this row is the first or last and update the margins.
if (row.selection()) { if (row.selection()) {
if (row.sel_beg == 0) if (row.sel_beg == 0)
row.begin_margin_sel = sel_beg.pit() < pit; row.change(row.begin_margin_sel, sel_beg.pit() < pit);
if (row.sel_end == sel_end_par.lastpos()) if (row.sel_end == sel_end_par.lastpos())
row.end_margin_sel = sel_end.pit() > pit; row.change(row.end_margin_sel, sel_end.pit() > pit);
} }
// Row signature; has row changed since last paint? // has row changed since last paint?
row.setCrc(pm.computeRowSignature(row, *bv_));
bool row_has_changed = row.changed() bool row_has_changed = row.changed()
|| bv_->hadHorizScrollOffset(text_, pit, row.pos()); || bv_->hadHorizScrollOffset(text_, pit, row.pos())
|| bv_->needRepaint(text_, row);
// Take this opportunity to spellcheck the row contents. // Take this opportunity to spellcheck the row contents.
if (row_has_changed && pi.do_spellcheck && lyxrc.spellcheck_continuously) { if (row_has_changed && pi.do_spellcheck && lyxrc.spellcheck_continuously) {
text_->getPar(pit).spellCheck(); text_->getPar(pit).spellCheck();
} }
RowPainter rp(pi, *text_, row, row_x, y);
// Don't paint the row if a full repaint has not been requested // Don't paint the row if a full repaint has not been requested
// and if it has not changed. // and if it has not changed.
if (!pi.full_repaint && !row_has_changed) { if (!pi.full_repaint && !row_has_changed) {
// Paint only the insets if the text itself is // Paint only the insets if the text itself is
// unchanged. // unchanged.
rp.paintOnlyInsets(); rp.paintOnlyInsets();
row.changed(false);
y += row.descent(); y += row.descent();
continue; continue;
} }
@ -1905,21 +1918,28 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
LYXERR(Debug::PAINTING, "Clear rect@(" LYXERR(Debug::PAINTING, "Clear rect@("
<< max(row_x, 0) << ", " << y - row.ascent() << ")=" << max(row_x, 0) << ", " << y - row.ascent() << ")="
<< width() << " x " << row.height()); << width() << " x " << row.height());
pi.pain.fillRectangle(max(row_x, 0), y - row.ascent(), // FIXME: this is a hack. We know that at least this
width(), row.height(), pi.background_color); // amount of pixels can be cleared on right and left.
// Doing so gets rid of caret ghosts when the cursor is at
// the begining/end of row. However, it will not work if
// the caret has a ridiculous width like 6. (see ticket
// #10797)
pi.pain.fillRectangle(max(row_x, 0) - Inset::TEXT_TO_INSET_OFFSET,
y - row.ascent(),
width() + 2 * Inset::TEXT_TO_INSET_OFFSET,
row.height(), pi.background_color);
} }
// Instrumentation for testing row cache (see also // Instrumentation for testing row cache (see also
// 12 lines lower): // 12 lines lower):
if (lyxerr.debugging(Debug::PAINTING) if (lyxerr.debugging(Debug::PAINTING)
&& (row.selection() || pi.full_repaint || row_has_changed)) { && (row.selection() || pi.full_repaint || row_has_changed)) {
string const foreword = text_->isMainText() ? string const foreword = text_->isMainText() ? "main text redraw "
"main text redraw " : "inset text redraw: "; : "inset text redraw: ";
LYXERR(Debug::PAINTING, foreword << "pit=" << pit << " row=" << i LYXERR0(foreword << "pit=" << pit << " row=" << i
<< " row_selection=" << row.selection() << (row.selection() ? " row_selection": "")
<< " full_repaint=" << pi.full_repaint << (pi.full_repaint ? " full_repaint" : "")
<< " row_has_changed=" << row_has_changed << (row_has_changed ? " row_has_changed" : ""));
<< " drawingEnabled=" << pi.pain.isDrawingEnabled());
} }
// Backup full_repaint status and force full repaint // Backup full_repaint status and force full repaint
@ -1930,7 +1950,8 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
rp.paintSelection(); rp.paintSelection();
rp.paintAppendix(); rp.paintAppendix();
rp.paintDepthBar(); rp.paintDepthBar();
rp.paintChangeBar(); if (row.needsChangeBar())
rp.paintChangeBar();
if (i == 0 && !row.isRTL()) if (i == 0 && !row.isRTL())
rp.paintFirst(); rp.paintFirst();
if (i == nrows - 1 && row.isRTL()) if (i == nrows - 1 && row.isRTL())
@ -1944,11 +1965,25 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
row_x + row.right_x() > bv_->workWidth()); row_x + row.right_x() > bv_->workWidth());
y += row.descent(); y += row.descent();
#if 0
// This debug code shows on screen which rows are repainted.
// FIXME: since the updates related to caret blinking restrict
// the painter to a small rectangle, the numbers are not
// updated when this happens. Change the code in
// GuiWorkArea::Private::show/hideCaret if this is important.
static int count = 0;
++count;
FontInfo fi(sane_font);
fi.setSize(FONT_SIZE_TINY);
fi.setColor(Color_red);
pi.pain.text(row_x, y, convert<docstring>(count), fi);
#endif
// Restore full_repaint status. // Restore full_repaint status.
pi.full_repaint = tmp; pi.full_repaint = tmp;
row.changed(false);
} }
// Re-enable screen drawing for future use of the painter.
pi.pain.setDrawingEnabled(true);
//LYXERR(Debug::PAINTING, "."); //LYXERR(Debug::PAINTING, ".");
} }

View File

@ -62,6 +62,11 @@ public:
/// ///
void newParMetricsUp(); void newParMetricsUp();
/// The "nodraw" drawing stage for one single paragraph: set the
/// positions of the insets contained this paragraph in metrics
/// cache. Related to BufferView::updatePosCache.
void updatePosCache(pit_type pit) const;
/// Gets the fully instantiated font at a given position in a paragraph /// Gets the fully instantiated font at a given position in a paragraph
/// Basically the same routine as Paragraph::getFont() in Paragraph.cpp. /// Basically the same routine as Paragraph::getFont() in Paragraph.cpp.
/// The difference is that this one is used for displaying, and thus we /// The difference is that this one is used for displaying, and thus we

View File

@ -18,6 +18,7 @@
#include "Undo.h" #include "Undo.h"
#include "Buffer.h" #include "Buffer.h"
#include "BufferList.h"
#include "BufferParams.h" #include "BufferParams.h"
#include "buffer_funcs.h" #include "buffer_funcs.h"
#include "Cursor.h" #include "Cursor.h"
@ -40,6 +41,7 @@
#include <algorithm> #include <algorithm>
#include <deque> #include <deque>
#include <set>
using namespace std; using namespace std;
using namespace lyx::support; using namespace lyx::support;
@ -645,22 +647,32 @@ void Undo::recordUndoFullBuffer(CursorData const & cur)
/// UndoGroupHelper class stuff /// UndoGroupHelper class stuff
/** FIXME: handle restarted groups class UndoGroupHelper::Impl {
* It may happen that the buffers are visited in order buffer1, friend class UndoGroupHelper;
* buffer2, buffer1. In this case, we want to have only one undo group set<Buffer *> buffers_;
* in buffer1. One solution is to replace buffer_ with a set<Buffer*>, };
* but I am not sure yet how to do it. A use case is
* InsetLabel::updateReferences.
*/ UndoGroupHelper::UndoGroupHelper(Buffer * buf) : d(new UndoGroupHelper::Impl)
{
resetBuffer(buf);
}
UndoGroupHelper::~UndoGroupHelper()
{
for (Buffer * buf : d->buffers_)
if (theBufferList().isLoaded(buf) || theBufferList().isInternal(buf))
buf->undo().endUndoGroup();
delete d;
}
void UndoGroupHelper::resetBuffer(Buffer * buf) void UndoGroupHelper::resetBuffer(Buffer * buf)
{ {
if (buf == buffer_) if (buf && d->buffers_.count(buf) == 0) {
return; d->buffers_.insert(buf);
if (buffer_) buf->undo().beginUndoGroup();
buffer_->undo().endUndoGroup(); }
buffer_ = buf;
if (buffer_)
buffer_->undo().beginUndoGroup();
} }

View File

@ -135,15 +135,9 @@ private:
*/ */
class UndoGroupHelper { class UndoGroupHelper {
public: public:
UndoGroupHelper(Buffer * buf = 0) : buffer_(0) UndoGroupHelper(Buffer * buf = 0);
{
resetBuffer(buf);
}
~UndoGroupHelper() ~UndoGroupHelper();
{
resetBuffer(0);
}
/** Close the current undo group if necessary and create a new one /** Close the current undo group if necessary and create a new one
* for buffer \c buf. * for buffer \c buf.
@ -151,7 +145,8 @@ public:
void resetBuffer(Buffer * buf); void resetBuffer(Buffer * buf);
private: private:
Buffer * buffer_; class Impl;
Impl * const d;
}; };

View File

@ -17,6 +17,7 @@ liblyxfrontends_a_SOURCES = \
Delegates.h \ Delegates.h \
KeyModifier.h \ KeyModifier.h \
KeySymbol.h \ KeySymbol.h \
NullPainter.h \
Painter.h \ Painter.h \
Clipboard.h \ Clipboard.h \
Selection.h \ Selection.h \

109
src/frontends/NullPainter.h Normal file
View File

@ -0,0 +1,109 @@
// -*- C++ -*-
/**
* \file NullPainter.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author unknown
* \author John Levon
* \author Jean-Marc Lasgouttes
*
* Full author contact details are available in file CREDITS.
*/
#ifndef NULLPAINTER_H
#define NULLPAINTER_H
#include "Painter.h"
namespace lyx {
namespace frontend {
/**
* NullPainter - A painter instance that does nothing
*/
class NullPainter : public Painter {
public:
NullPainter() : Painter(1) {}
~NullPainter() {}
/// draw a line from point to point
void line(int, int, int, int, Color,
line_style = line_solid, int = thin_line) {}
///
void lines(int const *, int const *, int, Color,
fill_style = fill_none, line_style = line_solid,
int = thin_line) {}
///
void path(int const *, int const *, int const *, int const *,
int const *, int const *, int, Color,
fill_style = fill_none, line_style = line_solid, int = thin_line) {}
/// draw a rectangle
void rectangle(int, int, int, int, Color,
line_style = line_solid, int = thin_line) {}
/// draw a filled rectangle
void fillRectangle(int, int, int, int, Color) {}
/// draw an arc
void arc(int, int, unsigned int, unsigned int, int, int, Color) {}
/// draw a pixel
void point(int, int, Color) {}
/// draw an image from the image cache
void image(int, int, int, int, graphics::Image const &) {}
/// draw a string
void text(int, int, docstring const &, FontInfo const &) {}
/// draw a char
void text(int, int, char_type, FontInfo const &) {}
/// draw a string
void text(int, int, docstring const &, Font const &, double, double) {}
///
void text(int, int, docstring const &, Font const &,
Color, size_type, size_type, double, double) {}
/// This painter does not paint
bool isNull() const { return true; }
/// draw the underbar, strikeout, xout, uuline and uwave font attributes
void textDecoration(FontInfo const &, int, int, int) {}
/**
* Draw a string and enclose it inside a rectangle. If
* back color is specified, the background is cleared with
* the given color. If frame is specified, a thin frame is drawn
* around the text with the given color.
*/
void rectText(int, int, docstring const &,
FontInfo const &, Color, Color) {}
/// draw a string and enclose it inside a button frame
void buttonText(int, int, docstring const &,
FontInfo const &, Color, Color, int) {}
/// draw a character of a preedit string for cjk support.
int preeditText(int, int, char_type, FontInfo const &,
preedit_style) { return 0; }
/// start monochrome painting mode, i.e. map every color into [min,max]
void enterMonochromeMode(Color const &, Color const &) {}
/// leave monochrome painting mode
void leaveMonochromeMode() {}
/// draws a wavy line that can be used for underlining.
void wavyHorizontalLine(int, int, int, ColorCode) {}
};
} // namespace frontend
} // namespace lyx
#endif // NULLPAINTER_H

View File

@ -49,7 +49,7 @@ namespace frontend {
*/ */
class Painter { class Painter {
public: public:
Painter(double pixel_ratio) : drawing_enabled_(true), pixel_ratio_(pixel_ratio) {} Painter(double pixel_ratio) : pixel_ratio_(pixel_ratio) {}
static const int thin_line; static const int thin_line;
@ -147,11 +147,8 @@ public:
Color other, size_type from, size_type to, Color other, size_type from, size_type to,
double wordspacing, double textwidth) = 0; double wordspacing, double textwidth) = 0;
void setDrawingEnabled(bool drawing_enabled) // Returns true if the painter does not actually paint.
{ drawing_enabled_ = drawing_enabled; } virtual bool isNull() const = 0;
/// Indicate wether real screen drawing shall be done or not.
bool isDrawingEnabled() const { return drawing_enabled_; }
double pixelRatio() const { return pixel_ratio_; } double pixelRatio() const { return pixel_ratio_; }
@ -183,8 +180,6 @@ public:
/// draws a wavy line that can be used for underlining. /// draws a wavy line that can be used for underlining.
virtual void wavyHorizontalLine(int x, int y, int width, ColorCode col) = 0; virtual void wavyHorizontalLine(int x, int y, int width, ColorCode col) = 0;
private: private:
///
bool drawing_enabled_;
/// Ratio between physical pixels and device-independent pixels /// Ratio between physical pixels and device-independent pixels
double pixel_ratio_; double pixel_ratio_;
}; };

View File

@ -36,8 +36,8 @@ public:
/// ///
virtual ~WorkArea() {} virtual ~WorkArea() {}
/// redraw the screen, without using existing pixmap /// Update metrics if needed and schedule a paint event
virtual void redraw(bool update_metrics) = 0; virtual void scheduleRedraw(bool update_metrics) = 0;
/// close this work area. /// close this work area.
/// Slot for Buffer::closing signal. /// Slot for Buffer::closing signal.

View File

@ -35,7 +35,7 @@ void WorkAreaManager::remove(WorkArea * wa)
void WorkAreaManager::redrawAll(bool update_metrics) void WorkAreaManager::redrawAll(bool update_metrics)
{ {
for (WorkArea * wa : work_areas_) for (WorkArea * wa : work_areas_)
wa->redraw(update_metrics); wa->scheduleRedraw(update_metrics);
} }

View File

@ -16,6 +16,8 @@
#include "LyXFileDialog.h" #include "LyXFileDialog.h"
#include "qt_helpers.h" #include "qt_helpers.h"
#include "LyXRC.h"
#include "support/debug.h" #include "support/debug.h"
#include "support/FileName.h" #include "support/FileName.h"
#include "support/filetools.h" #include "support/filetools.h"
@ -24,7 +26,9 @@
#include <string> #include <string>
/** when this is defined, the code will use #include <QApplication>
/** when LyXRC::use_native_filedialog is true, we use
* QFileDialog::getOpenFileName and friends to create filedialogs. * QFileDialog::getOpenFileName and friends to create filedialogs.
* Effects: * Effects:
* - the dialog does not use the quick directory buttons (Button * - the dialog does not use the quick directory buttons (Button
@ -35,13 +39,6 @@
* *
* Therefore there is a tradeoff in enabling or disabling this (JMarc) * Therefore there is a tradeoff in enabling or disabling this (JMarc)
*/ */
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
#define USE_NATIVE_FILEDIALOG 1
#endif
#ifdef USE_NATIVE_FILEDIALOG
#include <QApplication>
#endif
namespace lyx { namespace lyx {
@ -91,38 +88,38 @@ FileDialog::Result FileDialog::save(QString const & path,
FileDialog::Result result; FileDialog::Result result;
result.first = FileDialog::Chosen; result.first = FileDialog::Chosen;
#ifdef USE_NATIVE_FILEDIALOG if (lyxrc.use_native_filedialog) {
QString const startsWith = makeAbsPath(suggested, path); QString const startsWith = makeAbsPath(suggested, path);
QString const name = QString const name =
QFileDialog::getSaveFileName(qApp->focusWidget(), QFileDialog::getSaveFileName(qApp->focusWidget(),
title_, startsWith, filters.join(";;"), title_, startsWith, filters.join(";;"),
selectedFilter, QFileDialog::DontConfirmOverwrite); selectedFilter, QFileDialog::DontConfirmOverwrite);
if (name.isNull()) if (name.isNull())
result.first = FileDialog::Later; result.first = FileDialog::Later;
else else
result.second = toqstr(os::internal_path(fromqstr(name))); result.second = toqstr(os::internal_path(fromqstr(name)));
#else } else {
LyXFileDialog dlg(title_, path, filters, private_->b1, private_->b2); LyXFileDialog dlg(title_, path, filters, private_->b1, private_->b2);
dlg.setFileMode(QFileDialog::AnyFile); dlg.setFileMode(QFileDialog::AnyFile);
dlg.setAcceptMode(QFileDialog::AcceptSave); dlg.setAcceptMode(QFileDialog::AcceptSave);
dlg.setConfirmOverwrite(false); dlg.setConfirmOverwrite(false);
if (selectedFilter != 0 && !selectedFilter->isEmpty()) if (selectedFilter != 0 && !selectedFilter->isEmpty())
dlg.selectNameFilter(*selectedFilter); dlg.selectNameFilter(*selectedFilter);
if (!suggested.isEmpty()) if (!suggested.isEmpty())
dlg.selectFile(suggested); dlg.selectFile(suggested);
LYXERR(Debug::GUI, "Synchronous FileDialog: "); LYXERR(Debug::GUI, "Synchronous FileDialog: ");
int res = dlg.exec(); int res = dlg.exec();
LYXERR(Debug::GUI, "result " << res); LYXERR(Debug::GUI, "result " << res);
if (res == QDialog::Accepted) if (res == QDialog::Accepted)
result.second = internalPath(dlg.selectedFiles()[0]); result.second = internalPath(dlg.selectedFiles()[0]);
else else
result.first = FileDialog::Later; result.first = FileDialog::Later;
if (selectedFilter != 0) if (selectedFilter != 0)
*selectedFilter = dlg.selectedNameFilter(); *selectedFilter = dlg.selectedNameFilter();
dlg.hide(); dlg.hide();
#endif }
return result; return result;
} }
@ -143,29 +140,29 @@ FileDialog::Result FileDialog::open(QString const & path,
FileDialog::Result result; FileDialog::Result result;
result.first = FileDialog::Chosen; result.first = FileDialog::Chosen;
#ifdef USE_NATIVE_FILEDIALOG if (lyxrc.use_native_filedialog) {
QString const startsWith = makeAbsPath(suggested, path); QString const startsWith = makeAbsPath(suggested, path);
QString const file = QFileDialog::getOpenFileName(qApp->focusWidget(), QString const file = QFileDialog::getOpenFileName(qApp->focusWidget(),
title_, startsWith, filters.join(";;")); title_, startsWith, filters.join(";;"));
if (file.isNull()) if (file.isNull())
result.first = FileDialog::Later; result.first = FileDialog::Later;
else else
result.second = internalPath(file); result.second = internalPath(file);
#else } else {
LyXFileDialog dlg(title_, path, filters, private_->b1, private_->b2); LyXFileDialog dlg(title_, path, filters, private_->b1, private_->b2);
if (!suggested.isEmpty()) if (!suggested.isEmpty())
dlg.selectFile(suggested); dlg.selectFile(suggested);
LYXERR(Debug::GUI, "Synchronous FileDialog: "); LYXERR(Debug::GUI, "Synchronous FileDialog: ");
int res = dlg.exec(); int res = dlg.exec();
LYXERR(Debug::GUI, "result " << res); LYXERR(Debug::GUI, "result " << res);
if (res == QDialog::Accepted) if (res == QDialog::Accepted)
result.second = internalPath(dlg.selectedFiles()[0]); result.second = internalPath(dlg.selectedFiles()[0]);
else else
result.first = FileDialog::Later; result.first = FileDialog::Later;
dlg.hide(); dlg.hide();
#endif }
return result; return result;
} }
@ -178,33 +175,33 @@ FileDialog::Result FileDialog::opendir(QString const & path,
FileDialog::Result result; FileDialog::Result result;
result.first = FileDialog::Chosen; result.first = FileDialog::Chosen;
#ifdef USE_NATIVE_FILEDIALOG if (lyxrc.use_native_filedialog) {
QString const startsWith = toqstr(makeAbsPath(fromqstr(suggested), QString const startsWith =
fromqstr(path)).absFileName()); toqstr(makeAbsPath(fromqstr(suggested), fromqstr(path)).absFileName());
QString const dir = QFileDialog::getExistingDirectory(qApp->focusWidget(), QString const dir =
title_, startsWith); QFileDialog::getExistingDirectory(qApp->focusWidget(), title_, startsWith);
if (dir.isNull()) if (dir.isNull())
result.first = FileDialog::Later; result.first = FileDialog::Later;
else else
result.second = toqstr(os::internal_path(fromqstr(dir))); result.second = toqstr(os::internal_path(fromqstr(dir)));
#else } else {
LyXFileDialog dlg(title_, path, QStringList(qt_("Directories")), LyXFileDialog dlg(title_, path, QStringList(qt_("Directories")),
private_->b1, private_->b2); private_->b1, private_->b2);
dlg.setFileMode(QFileDialog::DirectoryOnly); dlg.setFileMode(QFileDialog::DirectoryOnly);
if (!suggested.isEmpty()) if (!suggested.isEmpty())
dlg.selectFile(suggested); dlg.selectFile(suggested);
LYXERR(Debug::GUI, "Synchronous FileDialog: "); LYXERR(Debug::GUI, "Synchronous FileDialog: ");
int res = dlg.exec(); int res = dlg.exec();
LYXERR(Debug::GUI, "result " << res); LYXERR(Debug::GUI, "result " << res);
if (res == QDialog::Accepted) if (res == QDialog::Accepted)
result.second = internalPath(dlg.selectedFiles()[0]); result.second = internalPath(dlg.selectedFiles()[0]);
else else
result.first = FileDialog::Later; result.first = FileDialog::Later;
dlg.hide(); dlg.hide();
#endif }
return result; return result;
} }

View File

@ -65,8 +65,8 @@ FindAndReplaceWidget::FindAndReplaceWidget(GuiView & view)
replace_work_area_->setFrameStyle(QFrame::StyledPanel); replace_work_area_->setFrameStyle(QFrame::StyledPanel);
// We don't want two cursors blinking. // We don't want two cursors blinking.
find_work_area_->stopBlinkingCursor(); find_work_area_->stopBlinkingCaret();
replace_work_area_->stopBlinkingCursor(); replace_work_area_->stopBlinkingCaret();
} }

View File

@ -1395,9 +1395,9 @@ DispatchResult const & GuiApplication::dispatch(FuncRequest const & cmd)
if (current_view_ && current_view_->currentBufferView()) { if (current_view_ && current_view_->currentBufferView()) {
current_view_->currentBufferView()->cursor().saveBeforeDispatchPosXY(); current_view_->currentBufferView()->cursor().saveBeforeDispatchPosXY();
buffer = &current_view_->currentBufferView()->buffer(); buffer = &current_view_->currentBufferView()->buffer();
if (buffer)
buffer->undo().beginUndoGroup();
} }
// This handles undo groups automagically
UndoGroupHelper ugh(buffer);
DispatchResult dr; DispatchResult dr;
// redraw the screen at the end (first of the two drawing steps). // redraw the screen at the end (first of the two drawing steps).
@ -1406,10 +1406,6 @@ DispatchResult const & GuiApplication::dispatch(FuncRequest const & cmd)
dispatch(cmd, dr); dispatch(cmd, dr);
updateCurrentView(cmd, dr); updateCurrentView(cmd, dr);
// the buffer may have been closed by one action
if (theBufferList().isLoaded(buffer) || theBufferList().isInternal(buffer))
buffer->undo().endUndoGroup();
d->dispatch_result_ = dr; d->dispatch_result_ = dr;
return d->dispatch_result_; return d->dispatch_result_;
} }
@ -1439,7 +1435,7 @@ void GuiApplication::updateCurrentView(FuncRequest const & cmd, DispatchResult &
theSelection().haveSelection(bv->cursor().selection()); theSelection().haveSelection(bv->cursor().selection());
// update gui // update gui
current_view_->restartCursor(); current_view_->restartCaret();
} }
if (dr.needMessageUpdate()) { if (dr.needMessageUpdate()) {
// Some messages may already be translated, so we cannot use _() // Some messages may already be translated, so we cannot use _()
@ -1633,14 +1629,7 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr)
case LFUN_SCREEN_FONT_UPDATE: { case LFUN_SCREEN_FONT_UPDATE: {
// handle the screen font changes. // handle the screen font changes.
d->font_loader_.update(); d->font_loader_.update();
// Backup current_view_ dr.screenUpdate(Update::Force | Update::FitCursor);
GuiView * view = current_view_;
// Set current_view_ to zero to forbid GuiWorkArea::redraw()
// to skip the refresh.
current_view_ = 0;
theBufferList().changed(false);
// Restore current_view_
current_view_ = view;
break; break;
} }
@ -1873,8 +1862,8 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr)
// FIXME: this LFUN should also work without any view. // FIXME: this LFUN should also work without any view.
Buffer * buffer = (current_view_ && current_view_->documentBufferView()) Buffer * buffer = (current_view_ && current_view_->documentBufferView())
? &(current_view_->documentBufferView()->buffer()) : 0; ? &(current_view_->documentBufferView()->buffer()) : 0;
if (buffer) // This handles undo groups automagically
buffer->undo().beginUndoGroup(); UndoGroupHelper ugh(buffer);
while (!arg.empty()) { while (!arg.empty()) {
string first; string first;
arg = split(arg, first, ';'); arg = split(arg, first, ';');
@ -1882,9 +1871,6 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr)
func.setOrigin(cmd.origin()); func.setOrigin(cmd.origin());
dispatch(func); dispatch(func);
} }
// the buffer may have been closed by one action
if (theBufferList().isLoaded(buffer) || theBufferList().isInternal(buffer))
buffer->undo().endUndoGroup();
break; break;
} }
@ -2158,7 +2144,7 @@ void GuiApplication::processKeySym(KeySymbol const & keysym, KeyModifier state)
if (!keysym.isOK()) if (!keysym.isOK())
LYXERR(Debug::KEY, "Empty kbd action (probably composing)"); LYXERR(Debug::KEY, "Empty kbd action (probably composing)");
if (current_view_) if (current_view_)
current_view_->restartCursor(); current_view_->restartCaret();
return; return;
} }
@ -2218,7 +2204,7 @@ void GuiApplication::processKeySym(KeySymbol const & keysym, KeyModifier state)
if (!isPrintable(encoded_last_key)) { if (!isPrintable(encoded_last_key)) {
LYXERR(Debug::KEY, "Non-printable character! Omitting."); LYXERR(Debug::KEY, "Non-printable character! Omitting.");
if (current_view_) if (current_view_)
current_view_->restartCursor(); current_view_->restartCaret();
return; return;
} }
// The following modifier check is not needed on Mac. // The following modifier check is not needed on Mac.
@ -2240,7 +2226,7 @@ void GuiApplication::processKeySym(KeySymbol const & keysym, KeyModifier state)
{ {
if (current_view_) { if (current_view_) {
current_view_->message(_("Unknown function.")); current_view_->message(_("Unknown function."));
current_view_->restartCursor(); current_view_->restartCaret();
} }
return; return;
} }
@ -2255,7 +2241,7 @@ void GuiApplication::processKeySym(KeySymbol const & keysym, KeyModifier state)
LYXERR(Debug::KEY, "Unknown Action and not isText() -- giving up"); LYXERR(Debug::KEY, "Unknown Action and not isText() -- giving up");
if (current_view_) { if (current_view_) {
current_view_->message(_("Unknown function.")); current_view_->message(_("Unknown function."));
current_view_->restartCursor(); current_view_->restartCaret();
} }
return; return;
} }

View File

@ -27,6 +27,7 @@
#include "TextClass.h" #include "TextClass.h"
#include "FuncRequest.h" #include "FuncRequest.h"
#include "insets/InsetCitation.h"
#include "insets/InsetCommand.h" #include "insets/InsetCommand.h"
#include "support/debug.h" #include "support/debug.h"
@ -92,7 +93,7 @@ static vector<lyx::docstring> to_docstring_vector(QStringList const & qlist)
GuiCitation::GuiCitation(GuiView & lv) GuiCitation::GuiCitation(GuiView & lv)
: DialogView(lv, "citation", qt_("Citation")), : DialogView(lv, "citation", qt_("Citation")),
style_(QString()), literal_(false), params_(insetCode("citation")) style_(QString()), params_(insetCode("citation"))
{ {
setupUi(this); setupUi(this);
@ -232,12 +233,13 @@ void GuiCitation::on_restorePB_clicked()
{ {
init(); init();
updateFilterHint(); updateFilterHint();
filterPressed();
} }
void GuiCitation::on_literalCB_clicked() void GuiCitation::on_literalCB_clicked()
{ {
literal_ = literalCB->isChecked(); InsetCitation::last_literal = literalCB->isChecked();
changed(); changed();
} }
@ -768,7 +770,7 @@ void GuiCitation::init()
// if this is a new citation, we set the literal checkbox // if this is a new citation, we set the literal checkbox
// to its last set value. // to its last set value.
if (cited_keys_.isEmpty()) if (cited_keys_.isEmpty())
literalCB->setChecked(literal_); literalCB->setChecked(InsetCitation::last_literal);
else else
literalCB->setChecked(params_["literal"] == "true"); literalCB->setChecked(params_["literal"] == "true");
@ -1061,7 +1063,7 @@ void GuiCitation::saveSession(QSettings & settings) const
settings.setValue( settings.setValue(
sessionKey() + "/citestyle", style_); sessionKey() + "/citestyle", style_);
settings.setValue( settings.setValue(
sessionKey() + "/literal", literal_); sessionKey() + "/literal", InsetCitation::last_literal);
} }
@ -1073,7 +1075,8 @@ void GuiCitation::restoreSession()
casesense_->setChecked(settings.value(sessionKey() + "/casesensitive").toBool()); casesense_->setChecked(settings.value(sessionKey() + "/casesensitive").toBool());
instant_->setChecked(settings.value(sessionKey() + "/autofind", true).toBool()); instant_->setChecked(settings.value(sessionKey() + "/autofind", true).toBool());
style_ = settings.value(sessionKey() + "/citestyle").toString(); style_ = settings.value(sessionKey() + "/citestyle").toString();
literal_ = settings.value(sessionKey() + "/literal", false).toBool(); InsetCitation::last_literal =
settings.value(sessionKey() + "/literal", false).toBool();
updateFilterHint(); updateFilterHint();
} }

View File

@ -183,9 +183,6 @@ private:
/// last used citation style /// last used citation style
QString style_; QString style_;
/// last set value for literal
/// this is used only for new citations
bool literal_;
/// ///
GuiSelectionManager * selectionManager; GuiSelectionManager * selectionManager;
/// available keys. /// available keys.

View File

@ -470,6 +470,33 @@ PreambleModule::PreambleModule(QWidget * parent)
preambleTE->setWordWrapMode(QTextOption::NoWrap); preambleTE->setWordWrapMode(QTextOption::NoWrap);
setFocusProxy(preambleTE); setFocusProxy(preambleTE);
connect(preambleTE, SIGNAL(textChanged()), this, SIGNAL(changed())); connect(preambleTE, SIGNAL(textChanged()), this, SIGNAL(changed()));
connect(findLE, SIGNAL(textEdited(const QString &)), this, SLOT(checkFindButton()));
connect(findButtonPB, SIGNAL(clicked()), this, SLOT(findText()));
connect(findLE, SIGNAL(returnPressed()), this, SLOT(findText()));
checkFindButton();
// https://stackoverflow.com/questions/13027091/how-to-override-tab-width-in-qt
const int tabStop = 4;
QFontMetrics metrics(preambleTE->currentFont());
preambleTE->setTabStopWidth(tabStop * metrics.width(' '));
}
void PreambleModule::checkFindButton()
{
findButtonPB->setEnabled(!findLE->text().isEmpty());
}
void PreambleModule::findText()
{
bool const found = preambleTE->find(findLE->text());
if (!found) {
// wrap
QTextCursor qtcur = preambleTE->textCursor();
qtcur.movePosition(QTextCursor::Start);
preambleTE->setTextCursor(qtcur);
preambleTE->find(findLE->text());
}
} }
@ -529,6 +556,8 @@ void PreambleModule::closeEvent(QCloseEvent * e)
LocalLayout::LocalLayout(QWidget * parent) LocalLayout::LocalLayout(QWidget * parent)
: UiWidget<Ui::LocalLayoutUi>(parent), current_id_(0), validated_(false) : UiWidget<Ui::LocalLayoutUi>(parent), current_id_(0), validated_(false)
{ {
locallayoutTE->setFont(guiApp->typewriterSystemFont());
locallayoutTE->setWordWrapMode(QTextOption::NoWrap);
connect(locallayoutTE, SIGNAL(textChanged()), this, SLOT(textChanged())); connect(locallayoutTE, SIGNAL(textChanged()), this, SLOT(textChanged()));
connect(validatePB, SIGNAL(clicked()), this, SLOT(validatePressed())); connect(validatePB, SIGNAL(clicked()), this, SLOT(validatePressed()));
connect(convertPB, SIGNAL(clicked()), this, SLOT(convertPressed())); connect(convertPB, SIGNAL(clicked()), this, SLOT(convertPressed()));
@ -1217,7 +1246,7 @@ GuiDocument::GuiDocument(GuiView & lv)
setSectionResizeMode(mathsModule->packagesTW->horizontalHeader(), QHeaderView::Stretch); setSectionResizeMode(mathsModule->packagesTW->horizontalHeader(), QHeaderView::Stretch);
map<string, string> const & packages = BufferParams::auto_packages(); map<string, string> const & packages = BufferParams::auto_packages();
mathsModule->packagesTW->setRowCount(packages.size()); mathsModule->packagesTW->setRowCount(packages.size());
int i = 0; int packnum = 0;
for (map<string, string>::const_iterator it = packages.begin(); for (map<string, string>::const_iterator it = packages.begin();
it != packages.end(); ++it) { it != packages.end(); ++it) {
docstring const package = from_ascii(it->first); docstring const package = from_ascii(it->first);
@ -1248,11 +1277,35 @@ GuiDocument::GuiDocument(GuiView & lv)
autoRB->setToolTip(autoTooltip); autoRB->setToolTip(autoTooltip);
alwaysRB->setToolTip(alwaysTooltip); alwaysRB->setToolTip(alwaysTooltip);
neverRB->setToolTip(neverTooltip); neverRB->setToolTip(neverTooltip);
// Pack the buttons in a layout in order to get proper alignment
QWidget * autoRBWidget = new QWidget();
QHBoxLayout * autoRBLayout = new QHBoxLayout(autoRBWidget);
autoRBLayout->addWidget(autoRB);
autoRBLayout->setAlignment(Qt::AlignCenter);
autoRBLayout->setContentsMargins(0, 0, 0, 0);
autoRBWidget->setLayout(autoRBLayout);
QWidget * alwaysRBWidget = new QWidget();
QHBoxLayout * alwaysRBLayout = new QHBoxLayout(alwaysRBWidget);
alwaysRBLayout->addWidget(alwaysRB);
alwaysRBLayout->setAlignment(Qt::AlignCenter);
alwaysRBLayout->setContentsMargins(0, 0, 0, 0);
alwaysRBWidget->setLayout(alwaysRBLayout);
QWidget * neverRBWidget = new QWidget();
QHBoxLayout * neverRBLayout = new QHBoxLayout(neverRBWidget);
neverRBLayout->addWidget(neverRB);
neverRBLayout->setAlignment(Qt::AlignCenter);
neverRBLayout->setContentsMargins(0, 0, 0, 0);
neverRBWidget->setLayout(neverRBLayout);
QTableWidgetItem * pack = new QTableWidgetItem(toqstr(package)); QTableWidgetItem * pack = new QTableWidgetItem(toqstr(package));
mathsModule->packagesTW->setItem(i, 0, pack);
mathsModule->packagesTW->setCellWidget(i, 1, autoRB); mathsModule->packagesTW->setItem(packnum, 0, pack);
mathsModule->packagesTW->setCellWidget(i, 2, alwaysRB); mathsModule->packagesTW->setCellWidget(packnum, 1, autoRBWidget);
mathsModule->packagesTW->setCellWidget(i, 3, neverRB); mathsModule->packagesTW->setCellWidget(packnum, 2, alwaysRBWidget);
mathsModule->packagesTW->setCellWidget(packnum, 3, neverRBWidget);
connect(autoRB, SIGNAL(clicked()), connect(autoRB, SIGNAL(clicked()),
this, SLOT(change_adaptor())); this, SLOT(change_adaptor()));
@ -1260,7 +1313,7 @@ GuiDocument::GuiDocument(GuiView & lv)
this, SLOT(change_adaptor())); this, SLOT(change_adaptor()));
connect(neverRB, SIGNAL(clicked()), connect(neverRB, SIGNAL(clicked()),
this, SLOT(change_adaptor())); this, SLOT(change_adaptor()));
++i; ++packnum;
} }
connect(mathsModule->allPackagesAutoPB, SIGNAL(clicked()), connect(mathsModule->allPackagesAutoPB, SIGNAL(clicked()),
this, SLOT(allPackagesAuto())); this, SLOT(allPackagesAuto()));
@ -3001,17 +3054,19 @@ void GuiDocument::applyView()
if (!item) if (!item)
continue; continue;
int row = mathsModule->packagesTW->row(item); int row = mathsModule->packagesTW->row(item);
QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1);
QRadioButton * rb =
(QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1)->layout()->itemAt(0)->widget();
if (rb->isChecked()) { if (rb->isChecked()) {
bp_.use_package(it->first, BufferParams::package_auto); bp_.use_package(it->first, BufferParams::package_auto);
continue; continue;
} }
rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2); rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2)->layout()->itemAt(0)->widget();
if (rb->isChecked()) { if (rb->isChecked()) {
bp_.use_package(it->first, BufferParams::package_on); bp_.use_package(it->first, BufferParams::package_on);
continue; continue;
} }
rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3); rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3)->layout()->itemAt(0)->widget();
if (rb->isChecked()) if (rb->isChecked())
bp_.use_package(it->first, BufferParams::package_off); bp_.use_package(it->first, BufferParams::package_off);
} }
@ -3546,17 +3601,20 @@ void GuiDocument::paramsToDialog()
int row = mathsModule->packagesTW->row(item); int row = mathsModule->packagesTW->row(item);
switch (bp_.use_package(it->first)) { switch (bp_.use_package(it->first)) {
case BufferParams::package_off: { case BufferParams::package_off: {
QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3); QRadioButton * rb =
(QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3)->layout()->itemAt(0)->widget();
rb->setChecked(true); rb->setChecked(true);
break; break;
} }
case BufferParams::package_on: { case BufferParams::package_on: {
QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2); QRadioButton * rb =
(QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2)->layout()->itemAt(0)->widget();
rb->setChecked(true); rb->setChecked(true);
break; break;
} }
case BufferParams::package_auto: { case BufferParams::package_auto: {
QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1); QRadioButton * rb =
(QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1)->layout()->itemAt(0)->widget();
rb->setChecked(true); rb->setChecked(true);
break; break;
} }
@ -4328,7 +4386,8 @@ void GuiDocument::dispatchParams()
// We need a non-const buffer object. // We need a non-const buffer object.
Buffer & buf = const_cast<BufferView *>(bufferview())->buffer(); Buffer & buf = const_cast<BufferView *>(bufferview())->buffer();
// There may be several undo records; group them (bug #8998) // There may be several undo records; group them (bug #8998)
buf.undo().beginUndoGroup(); // This handles undo groups automagically
UndoGroupHelper ugh(&buf);
// This must come first so that a language change is correctly noticed // This must come first so that a language change is correctly noticed
setLanguage(); setLanguage();
@ -4395,10 +4454,6 @@ void GuiDocument::dispatchParams()
// If we used an LFUN, we would not need these two lines: // If we used an LFUN, we would not need these two lines:
BufferView * bv = const_cast<BufferView *>(bufferview()); BufferView * bv = const_cast<BufferView *>(bufferview());
bv->processUpdateFlags(Update::Force | Update::FitCursor); bv->processUpdateFlags(Update::Force | Update::FitCursor);
// Don't forget to close the group. Note that it is important
// to check that there is no early return in the method.
buf.undo().endUndoGroup();
} }
@ -4569,7 +4624,8 @@ void GuiDocument::allPackagesNot()
void GuiDocument::allPackages(int col) void GuiDocument::allPackages(int col)
{ {
for (int row = 0; row < mathsModule->packagesTW->rowCount(); ++row) { for (int row = 0; row < mathsModule->packagesTW->rowCount(); ++row) {
QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, col); QRadioButton * rb =
(QRadioButton*)mathsModule->packagesTW->cellWidget(row, col)->layout()->itemAt(0)->widget();
rb->setChecked(true); rb->setChecked(true);
} }
} }

View File

@ -332,10 +332,14 @@ private:
void closeEvent(QCloseEvent *); void closeEvent(QCloseEvent *);
void on_preambleTE_textChanged() { changed(); } void on_preambleTE_textChanged() { changed(); }
private:
typedef std::map<BufferId, std::pair<int,int> > Coords; typedef std::map<BufferId, std::pair<int,int> > Coords;
Coords preamble_coords_; Coords preamble_coords_;
BufferId current_id_; BufferId current_id_;
private Q_SLOTS:
///
void checkFindButton();
void findText();
}; };

View File

@ -493,6 +493,9 @@ static void getCrop(external::ClipData & data,
void GuiExternal::updateContents() void GuiExternal::updateContents()
{ {
if (params_.filename.empty())
tab->setCurrentIndex(0);
string const name = string const name =
params_.filename.outputFileName(fromqstr(bufferFilePath())); params_.filename.outputFileName(fromqstr(bufferFilePath()));
fileED->setText(toqstr(name)); fileED->setText(toqstr(name));

View File

@ -31,9 +31,9 @@
#include "insets/InsetListingsParams.h" #include "insets/InsetListingsParams.h"
#include "insets/InsetInclude.h" #include "insets/InsetInclude.h"
#include <QPushButton>
#include <QCheckBox> #include <QCheckBox>
#include <QLineEdit> #include <QLineEdit>
#include <QPushButton>
#include <utility> #include <utility>

View File

@ -52,10 +52,10 @@ GuiPainter::GuiPainter(QPaintDevice * device, double pixel_ratio)
: QPainter(device), Painter(pixel_ratio), : QPainter(device), Painter(pixel_ratio),
use_pixmap_cache_(false) use_pixmap_cache_(false)
{ {
// new QPainter has default QPen: // set cache correctly
current_color_ = guiApp->colorCache().get(Color_black); current_color_ = pen().color();
current_ls_ = line_solid; current_ls_ = pen().style() == Qt::DotLine ? line_onoffdash : line_solid;
current_lw_ = thin_line; current_lw_ = pen().width();
} }
@ -171,9 +171,6 @@ void GuiPainter::leaveMonochromeMode()
void GuiPainter::point(int x, int y, Color col) void GuiPainter::point(int x, int y, Color col)
{ {
if (!isDrawingEnabled())
return;
setQPainterPen(computeColor(col)); setQPainterPen(computeColor(col));
drawPoint(x, y); drawPoint(x, y);
} }
@ -184,9 +181,6 @@ void GuiPainter::line(int x1, int y1, int x2, int y2,
line_style ls, line_style ls,
int lw) int lw)
{ {
if (!isDrawingEnabled())
return;
setQPainterPen(computeColor(col), ls, lw); setQPainterPen(computeColor(col), ls, lw);
bool const do_antialiasing = renderHints() & TextAntialiasing bool const do_antialiasing = renderHints() & TextAntialiasing
&& x1 != x2 && y1 != y2 && ls != line_solid_aliased; && x1 != x2 && y1 != y2 && ls != line_solid_aliased;
@ -202,9 +196,6 @@ void GuiPainter::lines(int const * xp, int const * yp, int np,
line_style ls, line_style ls,
int lw) int lw)
{ {
if (!isDrawingEnabled())
return;
// double the size if needed // double the size if needed
// FIXME THREAD // FIXME THREAD
static QVector<QPoint> points(32); static QVector<QPoint> points(32);
@ -247,9 +238,6 @@ void GuiPainter::path(int const * xp, int const * yp,
line_style ls, line_style ls,
int lw) int lw)
{ {
if (!isDrawingEnabled())
return;
QPainterPath bpath; QPainterPath bpath;
// This is the starting point, so its control points are meaningless // This is the starting point, so its control points are meaningless
bpath.moveTo(xp[0], yp[0]); bpath.moveTo(xp[0], yp[0]);
@ -278,9 +266,6 @@ void GuiPainter::rectangle(int x, int y, int w, int h,
line_style ls, line_style ls,
int lw) int lw)
{ {
if (!isDrawingEnabled())
return;
setQPainterPen(computeColor(col), ls, lw); setQPainterPen(computeColor(col), ls, lw);
drawRect(x, y, w, h); drawRect(x, y, w, h);
} }
@ -288,9 +273,6 @@ void GuiPainter::rectangle(int x, int y, int w, int h,
void GuiPainter::fillRectangle(int x, int y, int w, int h, Color col) void GuiPainter::fillRectangle(int x, int y, int w, int h, Color col)
{ {
if (!isDrawingEnabled())
return;
fillRect(x, y, w, h, guiApp->colorCache().get(col)); fillRect(x, y, w, h, guiApp->colorCache().get(col));
} }
@ -298,9 +280,6 @@ void GuiPainter::fillRectangle(int x, int y, int w, int h, Color col)
void GuiPainter::arc(int x, int y, unsigned int w, unsigned int h, void GuiPainter::arc(int x, int y, unsigned int w, unsigned int h,
int a1, int a2, Color col) int a1, int a2, Color col)
{ {
if (!isDrawingEnabled())
return;
// LyX usings 1/64ths degree, Qt usings 1/16th // LyX usings 1/64ths degree, Qt usings 1/16th
setQPainterPen(computeColor(col)); setQPainterPen(computeColor(col));
bool const do_antialiasing = renderHints() & TextAntialiasing; bool const do_antialiasing = renderHints() & TextAntialiasing;
@ -317,9 +296,6 @@ void GuiPainter::image(int x, int y, int w, int h, graphics::Image const & i)
fillRectangle(x, y, w, h, Color_graphicsbg); fillRectangle(x, y, w, h, Color_graphicsbg);
if (!isDrawingEnabled())
return;
QImage const image = qlimage.image(); QImage const image = qlimage.image();
QRectF const drect = QRectF(x, y, w, h); QRectF const drect = QRectF(x, y, w, h);
QRectF const srect = QRectF(0, 0, image.width(), image.height()); QRectF const srect = QRectF(0, 0, image.width(), image.height());
@ -391,7 +367,7 @@ void GuiPainter::text(int x, int y, docstring const & s,
double const wordspacing, double const tw) double const wordspacing, double const tw)
{ {
//LYXERR0("text: x=" << x << ", s=" << s); //LYXERR0("text: x=" << x << ", s=" << s);
if (s.empty() || !isDrawingEnabled()) if (s.empty())
return; return;
/* Caution: The following ucs4 to QString conversions work for symbol fonts /* Caution: The following ucs4 to QString conversions work for symbol fonts

View File

@ -37,6 +37,9 @@ public:
GuiPainter(QPaintDevice *, double pixel_ratio); GuiPainter(QPaintDevice *, double pixel_ratio);
virtual ~GuiPainter(); virtual ~GuiPainter();
/// This painter paints
virtual bool isNull() const { return false; }
/// draw a line from point to point /// draw a line from point to point
virtual void line( virtual void line(
int x1, int y1, int x1, int y1,

View File

@ -1882,7 +1882,8 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
case LFUN_BUFFER_RELOAD: case LFUN_BUFFER_RELOAD:
enable = doc_buffer && !doc_buffer->isUnnamed() enable = doc_buffer && !doc_buffer->isUnnamed()
&& doc_buffer->fileName().exists() && !doc_buffer->isClean(); && doc_buffer->fileName().exists()
&& (!doc_buffer->isClean() || doc_buffer->notifiesExternalModification());
break; break;
case LFUN_BUFFER_CHILD_OPEN: case LFUN_BUFFER_CHILD_OPEN:
@ -2262,8 +2263,10 @@ Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
setBuffer(newBuffer); setBuffer(newBuffer);
newBuffer->errors("Parse"); newBuffer->errors("Parse");
if (tolastfiles) if (tolastfiles) {
theSession().lastFiles().add(filename); theSession().lastFiles().add(filename);
theSession().writeFile();
}
return newBuffer; return newBuffer;
} }
@ -2802,6 +2805,7 @@ bool GuiView::saveBuffer(Buffer & b, FileName const & fn)
bool const success = (fn.empty() ? b.save() : b.saveAs(fn)); bool const success = (fn.empty() ? b.save() : b.saveAs(fn));
if (success) { if (success) {
theSession().lastFiles().add(b.fileName()); theSession().lastFiles().add(b.fileName());
theSession().writeFile();
return true; return true;
} }
@ -4191,7 +4195,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
// painting so we must reset it. // painting so we must reset it.
QPixmapCache::clear(); QPixmapCache::clear();
guiApp->fontLoader().update(); guiApp->fontLoader().update();
lyx::dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE)); dr.screenUpdate(Update::Force | Update::FitCursor);
break; break;
} }
@ -4387,19 +4391,19 @@ Buffer const * GuiView::updateInset(Inset const * inset)
continue; continue;
Buffer const * buffer = &(wa->bufferView().buffer()); Buffer const * buffer = &(wa->bufferView().buffer());
if (inset_buffer == buffer) if (inset_buffer == buffer)
wa->scheduleRedraw(); wa->scheduleRedraw(true);
} }
return inset_buffer; return inset_buffer;
} }
void GuiView::restartCursor() void GuiView::restartCaret()
{ {
/* When we move around, or type, it's nice to be able to see /* When we move around, or type, it's nice to be able to see
* the cursor immediately after the keypress. * the caret immediately after the keypress.
*/ */
if (d.current_work_area_) if (d.current_work_area_)
d.current_work_area_->startBlinkingCursor(); d.current_work_area_->startBlinkingCaret();
// Take this occasion to update the other GUI elements. // Take this occasion to update the other GUI elements.
updateDialogs(); updateDialogs();
@ -4468,7 +4472,7 @@ void GuiView::resetDialogs()
// Now update controls with current buffer. // Now update controls with current buffer.
guiApp->setCurrentView(this); guiApp->setCurrentView(this);
restoreLayout(); restoreLayout();
restartCursor(); restartCaret();
} }

View File

@ -116,7 +116,7 @@ public:
/// \return true if the \c FuncRequest has been dispatched. /// \return true if the \c FuncRequest has been dispatched.
void dispatch(FuncRequest const & cmd, DispatchResult & dr); void dispatch(FuncRequest const & cmd, DispatchResult & dr);
void restartCursor(); void restartCaret();
/// Update the completion popup and the inline completion state. /// Update the completion popup and the inline completion state.
/// If \c start is true, then a new completion might be started. /// If \c start is true, then a new completion might be started.
/// If \c keep is true, an active completion will be kept active /// If \c keep is true, an active completion will be kept active

View File

@ -16,7 +16,13 @@
#include "ColorCache.h" #include "ColorCache.h"
#include "FontLoader.h" #include "FontLoader.h"
#include "GuiApplication.h"
#include "GuiCompleter.h"
#include "GuiKeySymbol.h"
#include "GuiPainter.h"
#include "GuiView.h"
#include "Menus.h" #include "Menus.h"
#include "qt_helpers.h"
#include "Buffer.h" #include "Buffer.h"
#include "BufferList.h" #include "BufferList.h"
@ -26,19 +32,14 @@
#include "Cursor.h" #include "Cursor.h"
#include "Font.h" #include "Font.h"
#include "FuncRequest.h" #include "FuncRequest.h"
#include "GuiApplication.h"
#include "GuiCompleter.h"
#include "GuiKeySymbol.h"
#include "GuiPainter.h"
#include "GuiView.h"
#include "KeySymbol.h" #include "KeySymbol.h"
#include "Language.h" #include "Language.h"
#include "LyX.h" #include "LyX.h"
#include "LyXRC.h" #include "LyXRC.h"
#include "LyXVC.h" #include "LyXVC.h"
#include "qt_helpers.h"
#include "Text.h" #include "Text.h"
#include "TextMetrics.h" #include "TextMetrics.h"
#include "Undo.h"
#include "version.h" #include "version.h"
#include "graphics/GraphicsImage.h" #include "graphics/GraphicsImage.h"
@ -46,7 +47,6 @@
#include "support/convert.h" #include "support/convert.h"
#include "support/debug.h" #include "support/debug.h"
#include "support/gettext.h"
#include "support/lassert.h" #include "support/lassert.h"
#include "support/TempFile.h" #include "support/TempFile.h"
@ -68,7 +68,6 @@
#include <QMenu> #include <QMenu>
#include <QPainter> #include <QPainter>
#include <QPalette> #include <QPalette>
#include <QPixmapCache>
#include <QScrollBar> #include <QScrollBar>
#include <QStyleOption> #include <QStyleOption>
#include <QStylePainter> #include <QStylePainter>
@ -77,8 +76,6 @@
#include <QToolTip> #include <QToolTip>
#include <QMenuBar> #include <QMenuBar>
#include "support/bind.h"
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
@ -130,17 +127,15 @@ mouse_button::state q_motion_state(Qt::MouseButtons state)
namespace frontend { namespace frontend {
class CursorWidget { class CaretWidget {
public: public:
CursorWidget() : rtl_(false), l_shape_(false), completable_(false), CaretWidget() : rtl_(false), l_shape_(false), completable_(false),
show_(false), x_(0), cursor_width_(0) x_(0), caret_width_(0)
{ {}
recomputeWidth();
}
void draw(QPainter & painter) void draw(QPainter & painter)
{ {
if (!show_ || !rect_.isValid()) if (!rect_.isValid())
return; return;
int y = rect_.top(); int y = rect_.top();
@ -149,7 +144,7 @@ public:
int bot = rect_.bottom(); int bot = rect_.bottom();
// draw vertical line // draw vertical line
painter.fillRect(x_, y, cursor_width_, rect_.height(), color_); painter.fillRect(x_, y, caret_width_, rect_.height(), color_);
// draw RTL/LTR indication // draw RTL/LTR indication
painter.setPen(color_); painter.setPen(color_);
@ -157,7 +152,7 @@ public:
if (rtl_) if (rtl_)
painter.drawLine(x_, bot, x_ - l, bot); painter.drawLine(x_, bot, x_ - l, bot);
else else
painter.drawLine(x_, bot, x_ + cursor_width_ + r, bot); painter.drawLine(x_, bot, x_ + caret_width_ + r, bot);
} }
// draw completion triangle // draw completion triangle
@ -168,8 +163,8 @@ public:
painter.drawLine(x_ - 1, m - d, x_ - 1 - d, m); painter.drawLine(x_ - 1, m - d, x_ - 1 - d, m);
painter.drawLine(x_ - 1, m + d, x_ - 1 - d, m); painter.drawLine(x_ - 1, m + d, x_ - 1 - d, m);
} else { } else {
painter.drawLine(x_ + cursor_width_, m - d, x_ + cursor_width_ + d, m); painter.drawLine(x_ + caret_width_, m - d, x_ + caret_width_ + d, m);
painter.drawLine(x_ + cursor_width_, m + d, x_ + cursor_width_ + d, m); painter.drawLine(x_ + caret_width_, m + d, x_ + caret_width_ + d, m);
} }
} }
} }
@ -203,38 +198,32 @@ public:
r = max(r, TabIndicatorWidth); r = max(r, TabIndicatorWidth);
} }
// compute overall rectangle //FIXME: LyXRC::cursor_width should be caret_width
rect_ = QRect(x - l, y, cursor_width_ + r + l, h); caret_width_ = lyxrc.cursor_width
}
void show(bool set_show = true) { show_ = set_show; }
void hide() { show_ = false; }
int cursorWidth() const { return cursor_width_; }
void recomputeWidth() {
cursor_width_ = lyxrc.cursor_width
? lyxrc.cursor_width ? lyxrc.cursor_width
: 1 + int((lyxrc.currentZoom + 50) / 200.0); : 1 + int((lyxrc.currentZoom + 50) / 200.0);
// compute overall rectangle
rect_ = QRect(x - l, y, caret_width_ + r + l, h);
} }
QRect const & rect() { return rect_; } QRect const & rect() { return rect_; }
private: private:
/// cursor is in RTL or LTR text /// caret is in RTL or LTR text
bool rtl_; bool rtl_;
/// indication for RTL or LTR /// indication for RTL or LTR
bool l_shape_; bool l_shape_;
/// triangle to show that a completion is available /// triangle to show that a completion is available
bool completable_; bool completable_;
/// ///
bool show_;
///
QColor color_; QColor color_;
/// rectangle, possibly with l_shape and completion triangle /// rectangle, possibly with l_shape and completion triangle
QRect rect_; QRect rect_;
/// x position (were the vertical line is drawn) /// x position (were the vertical line is drawn)
int x_; int x_;
/// the width of the vertical blinking bar
int cursor_width_; int caret_width_;
}; };
@ -246,13 +235,35 @@ SyntheticMouseEvent::SyntheticMouseEvent()
GuiWorkArea::Private::Private(GuiWorkArea * parent) GuiWorkArea::Private::Private(GuiWorkArea * parent)
: p(parent), screen_(0), buffer_view_(0), lyx_view_(0), : p(parent), buffer_view_(0), lyx_view_(0),
cursor_visible_(false), cursor_(0), caret_(0), caret_visible_(false),
need_resize_(false), schedule_redraw_(false), preedit_lines_(1), need_resize_(false), preedit_lines_(1),
pixel_ratio_(1.0), last_pixel_ratio_(1.0),
completer_(new GuiCompleter(p, p)), dialog_mode_(false), shell_escape_(false), completer_(new GuiCompleter(p, p)), dialog_mode_(false), shell_escape_(false),
read_only_(false), clean_(true), externally_modified_(false) read_only_(false), clean_(true), externally_modified_(false)
{ {
int const time = QApplication::cursorFlashTime() / 2;
if (time > 0) {
caret_timeout_.setInterval(time);
caret_timeout_.start();
} else {
// let's initialize this just to be safe
caret_timeout_.setInterval(500);
}
}
GuiWorkArea::Private::~Private()
{
// If something is wrong with the buffer, we can ignore it safely
try {
buffer_view_->buffer().workAreaManager().remove(p);
} catch(...) {}
delete buffer_view_;
delete caret_;
// Completer has a QObject parent and is thus automatically destroyed.
// See #4758.
// delete completer_;
} }
@ -287,24 +298,19 @@ double GuiWorkArea::pixelRatio() const
void GuiWorkArea::init() void GuiWorkArea::init()
{ {
// Setup the signals // Setup the signals
connect(&d->cursor_timeout_, SIGNAL(timeout()), connect(&d->caret_timeout_, SIGNAL(timeout()),
this, SLOT(toggleCursor())); this, SLOT(toggleCaret()));
int const time = QApplication::cursorFlashTime() / 2; // This connection is closed at the same time as this is destroyed.
if (time > 0) { d->synthetic_mouse_event_.timeout.timeout.connect([this](){
d->cursor_timeout_.setInterval(time); generateSyntheticMouseEvent();
d->cursor_timeout_.start(); });
} else {
// let's initialize this just to be safe
d->cursor_timeout_.setInterval(500);
}
d->resetScreen(); d->resetScreen();
// With Qt4.5 a mouse event will happen before the first paint event // With Qt4.5 a mouse event will happen before the first paint event
// so make sure that the buffer view has an up to date metrics. // so make sure that the buffer view has an up to date metrics.
d->buffer_view_->resize(viewport()->width(), viewport()->height()); d->buffer_view_->resize(viewport()->width(), viewport()->height());
d->cursor_ = new frontend::CursorWidget(); d->caret_ = new frontend::CaretWidget();
d->cursor_->hide();
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setAcceptDrops(true); setAcceptDrops(true);
@ -313,63 +319,33 @@ void GuiWorkArea::init()
setFrameStyle(QFrame::NoFrame); setFrameStyle(QFrame::NoFrame);
updateWindowTitle(); updateWindowTitle();
viewport()->setAutoFillBackground(false); d->updateCursorShape();
// We don't need double-buffering nor SystemBackground on
// the viewport because we have our own backing pixmap. // we paint our own background
viewport()->setAttribute(Qt::WA_NoSystemBackground); viewport()->setAttribute(Qt::WA_OpaquePaintEvent);
setFocusPolicy(Qt::StrongFocus); setFocusPolicy(Qt::StrongFocus);
d->setCursorShape(Qt::IBeamCursor);
// This connection is closed at the same time as this is destroyed.
d->synthetic_mouse_event_.timeout.timeout.connect([this](){
generateSyntheticMouseEvent();
});
LYXERR(Debug::GUI, "viewport width: " << viewport()->width() LYXERR(Debug::GUI, "viewport width: " << viewport()->width()
<< " viewport height: " << viewport()->height()); << " viewport height: " << viewport()->height());
// Enables input methods for asian languages. // Enables input methods for asian languages.
// Must be set when creating custom text editing widgets. // Must be set when creating custom text editing widgets.
setAttribute(Qt::WA_InputMethodEnabled, true); setAttribute(Qt::WA_InputMethodEnabled, true);
d->dialog_mode_ = false;
} }
GuiWorkArea::~GuiWorkArea() GuiWorkArea::~GuiWorkArea()
{ {
// If something is wrong with the buffer, we can ignore it safely
try {
d->buffer_view_->buffer().workAreaManager().remove(this);
} catch(...) {}
delete d->screen_;
delete d->buffer_view_;
delete d->cursor_;
// Completer has a QObject parent and is thus automatically destroyed.
// See #4758.
// delete completer_;
delete d; delete d;
} }
Qt::CursorShape GuiWorkArea::cursorShape() const
{
return viewport()->cursor().shape();
}
void GuiWorkArea::Private::setCursorShape(Qt::CursorShape shape)
{
p->viewport()->setCursor(shape);
}
void GuiWorkArea::Private::updateCursorShape() void GuiWorkArea::Private::updateCursorShape()
{ {
setCursorShape(buffer_view_->clickableInset() bool const clickable = buffer_view_ && buffer_view_->clickableInset();
? Qt::PointingHandCursor : Qt::IBeamCursor); p->viewport()->setCursor(clickable ? Qt::PointingHandCursor
: Qt::IBeamCursor);
} }
@ -436,14 +412,14 @@ BufferView const & GuiWorkArea::bufferView() const
} }
void GuiWorkArea::stopBlinkingCursor() void GuiWorkArea::stopBlinkingCaret()
{ {
d->cursor_timeout_.stop(); d->caret_timeout_.stop();
d->hideCursor(); d->hideCaret();
} }
void GuiWorkArea::startBlinkingCursor() void GuiWorkArea::startBlinkingCaret()
{ {
// do not show the cursor if the view is busy // do not show the cursor if the view is busy
if (view().busy()) if (view().busy())
@ -451,23 +427,32 @@ void GuiWorkArea::startBlinkingCursor()
Point p; Point p;
int h = 0; int h = 0;
d->buffer_view_->cursorPosAndHeight(p, h); d->buffer_view_->caretPosAndHeight(p, h);
// Don't start blinking if the cursor isn't on screen. // Don't start blinking if the cursor isn't on screen.
if (!d->buffer_view_->cursorInView(p, h)) if (!d->buffer_view_->cursorInView(p, h))
return; return;
d->showCursor(); d->showCaret();
//we're not supposed to cache this value. //we're not supposed to cache this value.
int const time = QApplication::cursorFlashTime() / 2; int const time = QApplication::cursorFlashTime() / 2;
if (time <= 0) if (time <= 0)
return; return;
d->cursor_timeout_.setInterval(time); d->caret_timeout_.setInterval(time);
d->cursor_timeout_.start(); d->caret_timeout_.start();
} }
void GuiWorkArea::redraw(bool update_metrics) void GuiWorkArea::toggleCaret()
{
if (d->caret_visible_)
d->hideCaret();
else
d->showCaret();
}
void GuiWorkArea::scheduleRedraw(bool update_metrics)
{ {
if (!isVisible()) if (!isVisible())
// No need to redraw in this case. // No need to redraw in this case.
@ -483,17 +468,14 @@ void GuiWorkArea::redraw(bool update_metrics)
d->buffer_view_->cursor().fixIfBroken(); d->buffer_view_->cursor().fixIfBroken();
} }
// update cursor position, because otherwise it has to wait until // update caret position, because otherwise it has to wait until
// the blinking interval is over // the blinking interval is over
if (d->cursor_visible_) { d->updateCaretGeometry();
d->hideCursor();
d->showCursor();
}
LYXERR(Debug::WORKAREA, "WorkArea::redraw screen"); LYXERR(Debug::WORKAREA, "WorkArea::redraw screen");
d->updateScreen(); viewport()->update();
update(0, 0, viewport()->width(), viewport()->height());
/// FIXME: is this still true now that paintEvent does the actual painting?
/// \warning: scrollbar updating *must* be done after the BufferView is drawn /// \warning: scrollbar updating *must* be done after the BufferView is drawn
/// because \c BufferView::updateScrollbar() is called in \c BufferView::draw(). /// because \c BufferView::updateScrollbar() is called in \c BufferView::draw().
d->updateScrollbar(); d->updateScrollbar();
@ -526,9 +508,9 @@ void GuiWorkArea::processKeySym(KeySymbol const & key, KeyModifier mod)
} }
// In order to avoid bad surprise in the middle of an operation, // In order to avoid bad surprise in the middle of an operation,
// we better stop the blinking cursor... // we better stop the blinking caret...
// the cursor gets restarted in GuiView::restartCursor() // the caret gets restarted in GuiView::restartCaret()
stopBlinkingCursor(); stopBlinkingCaret();
guiApp->processKeySym(key, mod); guiApp->processKeySym(key, mod);
} }
@ -546,9 +528,9 @@ void GuiWorkArea::Private::dispatch(FuncRequest const & cmd)
cmd.action() != LFUN_MOUSE_MOTION || cmd.button() != mouse_button::none; cmd.action() != LFUN_MOUSE_MOTION || cmd.button() != mouse_button::none;
// In order to avoid bad surprise in the middle of an operation, we better stop // In order to avoid bad surprise in the middle of an operation, we better stop
// the blinking cursor. // the blinking caret.
if (notJustMovingTheMouse) if (notJustMovingTheMouse)
p->stopBlinkingCursor(); p->stopBlinkingCaret();
buffer_view_->mouseEventDispatch(cmd); buffer_view_->mouseEventDispatch(cmd);
@ -568,8 +550,8 @@ void GuiWorkArea::Private::dispatch(FuncRequest const & cmd)
// FIXME: let GuiView take care of those. // FIXME: let GuiView take care of those.
lyx_view_->clearMessage(); lyx_view_->clearMessage();
// Show the cursor immediately after any operation // Show the caret immediately after any operation
p->startBlinkingCursor(); p->startBlinkingCaret();
} }
updateCursorShape(); updateCursorShape();
@ -580,18 +562,18 @@ void GuiWorkArea::Private::resizeBufferView()
{ {
// WARNING: Please don't put any code that will trigger a repaint here! // WARNING: Please don't put any code that will trigger a repaint here!
// We are already inside a paint event. // We are already inside a paint event.
p->stopBlinkingCursor(); p->stopBlinkingCaret();
// Warn our container (GuiView). // Warn our container (GuiView).
p->busy(true); p->busy(true);
Point point; Point point;
int h = 0; int h = 0;
buffer_view_->cursorPosAndHeight(point, h); buffer_view_->caretPosAndHeight(point, h);
bool const cursor_in_view = buffer_view_->cursorInView(point, h); bool const caret_in_view = buffer_view_->cursorInView(point, h);
buffer_view_->resize(p->viewport()->width(), p->viewport()->height()); buffer_view_->resize(p->viewport()->width(), p->viewport()->height());
if (cursor_in_view) if (caret_in_view)
buffer_view_->scrollToCursor(); buffer_view_->scrollToCursor();
updateScreen(); updateCaretGeometry();
// Update scrollbars which might have changed due different // Update scrollbars which might have changed due different
// BufferView dimension. This is especially important when the // BufferView dimension. This is especially important when the
@ -601,23 +583,20 @@ void GuiWorkArea::Private::resizeBufferView()
need_resize_ = false; need_resize_ = false;
p->busy(false); p->busy(false);
// Eventually, restart the cursor after the resize event. // Eventually, restart the caret after the resize event.
// We might be resizing even if the focus is on another widget so we only // We might be resizing even if the focus is on another widget so we only
// restart the cursor if we have the focus. // restart the caret if we have the focus.
if (p->hasFocus()) if (p->hasFocus())
QTimer::singleShot(50, p, SLOT(startBlinkingCursor())); QTimer::singleShot(50, p, SLOT(startBlinkingCaret()));
} }
void GuiWorkArea::Private::showCursor() void GuiWorkArea::Private::updateCaretGeometry()
{ {
if (cursor_visible_) Point point;
return;
Point p;
int h = 0; int h = 0;
buffer_view_->cursorPosAndHeight(p, h); buffer_view_->caretPosAndHeight(point, h);
if (!buffer_view_->cursorInView(p, h)) if (!buffer_view_->cursorInView(point, h))
return; return;
// RTL or not RTL // RTL or not RTL
@ -634,40 +613,41 @@ void GuiWorkArea::Private::showCursor()
if (realfont.language() == latex_language) if (realfont.language() == latex_language)
l_shape = false; l_shape = false;
// show cursor on screen // show caret on screen
Cursor & cur = buffer_view_->cursor(); Cursor & cur = buffer_view_->cursor();
bool completable = cur.inset().showCompletionCursor() bool completable = cur.inset().showCompletionCursor()
&& completer_->completionAvailable() && completer_->completionAvailable()
&& !completer_->popupVisible() && !completer_->popupVisible()
&& !completer_->inlineVisible(); && !completer_->inlineVisible();
cursor_visible_ = true; caret_visible_ = true;
cursor_->recomputeWidth();
//int cur_x = buffer_view_->getPos(cur).x_; //int cur_x = buffer_view_->getPos(cur).x_;
// We may have decided to slide the cursor row so that cursor // We may have decided to slide the cursor row so that caret
// is visible. // is visible.
p.x_ -= buffer_view_->horizScrollOffset(); point.x_ -= buffer_view_->horizScrollOffset();
showCursor(p.x_, p.y_, h, l_shape, isrtl, completable); caret_->update(point.x_, point.y_, h, l_shape, isrtl, completable);
} }
void GuiWorkArea::Private::hideCursor() void GuiWorkArea::Private::showCaret()
{ {
if (!cursor_visible_) if (caret_visible_)
return; return;
cursor_visible_ = false; updateCaretGeometry();
removeCursor(); p->viewport()->update(caret_->rect());
} }
void GuiWorkArea::toggleCursor() void GuiWorkArea::Private::hideCaret()
{ {
if (d->cursor_visible_) if (!caret_visible_)
d->hideCursor(); return;
else
d->showCursor(); caret_visible_ = false;
//if (!qApp->focusWidget())
p->viewport()->update(caret_->rect());
} }
@ -690,7 +670,7 @@ void GuiWorkArea::Private::updateScrollbar()
void GuiWorkArea::scrollTo(int value) void GuiWorkArea::scrollTo(int value)
{ {
stopBlinkingCursor(); stopBlinkingCaret();
d->buffer_view_->scrollDocView(value, true); d->buffer_view_->scrollDocView(value, true);
if (lyxrc.cursor_follows_scrollbar) { if (lyxrc.cursor_follows_scrollbar) {
@ -698,8 +678,8 @@ void GuiWorkArea::scrollTo(int value)
// FIXME: let GuiView take care of those. // FIXME: let GuiView take care of those.
d->lyx_view_->updateLayoutList(); d->lyx_view_->updateLayoutList();
} }
// Show the cursor immediately after any operation. // Show the caret immediately after any operation.
startBlinkingCursor(); startBlinkingCaret();
// FIXME QT5 // FIXME QT5
#ifdef Q_WS_X11 #ifdef Q_WS_X11
QApplication::syncX(); QApplication::syncX();
@ -805,7 +785,7 @@ void GuiWorkArea::focusInEvent(QFocusEvent * e)
d->lyx_view_->currentWorkArea()->bufferView().buffer().updateBuffer(); d->lyx_view_->currentWorkArea()->bufferView().buffer().updateBuffer();
} }
startBlinkingCursor(); startBlinkingCaret();
QAbstractScrollArea::focusInEvent(e); QAbstractScrollArea::focusInEvent(e);
} }
@ -813,7 +793,7 @@ void GuiWorkArea::focusInEvent(QFocusEvent * e)
void GuiWorkArea::focusOutEvent(QFocusEvent * e) void GuiWorkArea::focusOutEvent(QFocusEvent * e)
{ {
LYXERR(Debug::DEBUG, "GuiWorkArea::focusOutEvent(): " << this << endl); LYXERR(Debug::DEBUG, "GuiWorkArea::focusOutEvent(): " << this << endl);
stopBlinkingCursor(); stopBlinkingCaret();
QAbstractScrollArea::focusOutEvent(e); QAbstractScrollArea::focusOutEvent(e);
} }
@ -1176,157 +1156,31 @@ void GuiWorkArea::resizeEvent(QResizeEvent * ev)
} }
void GuiWorkArea::Private::update(int x, int y, int w, int h) void GuiWorkArea::Private::paintPreeditText(GuiPainter & pain)
{ {
p->viewport()->update(x, y, w, h); if (preedit_string_.empty())
}
void GuiWorkArea::paintEvent(QPaintEvent * ev)
{
QRectF const rc = ev->rect();
// LYXERR(Debug::PAINTING, "paintEvent begin: x: " << rc.x()
// << " y: " << rc.y() << " w: " << rc.width() << " h: " << rc.height());
if (d->needResize()) {
d->resetScreen();
d->resizeBufferView();
if (d->cursor_visible_) {
d->hideCursor();
d->showCursor();
}
}
QPainter pain(viewport());
double const pr = pixelRatio();
QRectF const rcs = QRectF(rc.x() * pr, rc.y() * pr, rc.width() * pr, rc.height() * pr);
if (lyxrc.use_qimage) {
QImage const & image = static_cast<QImage const &>(*d->screen_);
pain.drawImage(rc, image, rcs);
} else {
QPixmap const & pixmap = static_cast<QPixmap const &>(*d->screen_);
pain.drawPixmap(rc, pixmap, rcs);
}
d->cursor_->draw(pain);
ev->accept();
}
void GuiWorkArea::Private::updateScreen()
{
GuiPainter pain(screen_, p->pixelRatio());
buffer_view_->draw(pain);
}
void GuiWorkArea::Private::showCursor(int x, int y, int h,
bool l_shape, bool rtl, bool completable)
{
if (schedule_redraw_) {
// This happens when a graphic conversion is finished. As we don't know
// the size of the new graphics, it's better the update everything.
// We can't use redraw() here because this would trigger a infinite
// recursive loop with showCursor().
buffer_view_->resize(p->viewport()->width(), p->viewport()->height());
updateScreen();
updateScrollbar();
p->viewport()->update(QRect(0, 0, p->viewport()->width(), p->viewport()->height()));
schedule_redraw_ = false;
// Show the cursor immediately after the update.
hideCursor();
p->toggleCursor();
return; return;
}
cursor_->update(x, y, h, l_shape, rtl, completable);
cursor_->show();
p->viewport()->update(cursor_->rect());
}
void GuiWorkArea::Private::removeCursor()
{
cursor_->hide();
//if (!qApp->focusWidget())
p->viewport()->update(cursor_->rect());
}
void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
{
QString const & commit_string = e->commitString();
docstring const & preedit_string
= qstring_to_ucs4(e->preeditString());
if (!commit_string.isEmpty()) {
LYXERR(Debug::KEY, "preeditString: " << e->preeditString()
<< " commitString: " << e->commitString());
int key = 0;
// FIXME Iwami 04/01/07: we should take care also of UTF16 surrogates here.
for (int i = 0; i != commit_string.size(); ++i) {
QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string[i]);
keyPressEvent(&ev);
}
}
// Hide the cursor during the kana-kanji transformation.
if (preedit_string.empty())
startBlinkingCursor();
else
stopBlinkingCursor();
// last_width : for checking if last preedit string was/wasn't empty.
// FIXME THREAD && FIXME
// We could have more than one work area, right?
static bool last_width = false;
if (!last_width && preedit_string.empty()) {
// if last_width is last length of preedit string.
e->accept();
return;
}
GuiPainter pain(d->screen_, pixelRatio());
d->buffer_view_->updateMetrics();
d->buffer_view_->draw(pain);
// FIXME: shall we use real_current_font here? (see #10478) // FIXME: shall we use real_current_font here? (see #10478)
FontInfo font = d->buffer_view_->cursor().getFont().fontInfo(); FontInfo const font = buffer_view_->cursor().getFont().fontInfo();
FontMetrics const & fm = theFontMetrics(font); FontMetrics const & fm = theFontMetrics(font);
int height = fm.maxHeight(); int const height = fm.maxHeight();
int cur_x = d->cursor_->rect().left(); int cur_x = caret_->rect().left();
int cur_y = d->cursor_->rect().bottom(); int cur_y = caret_->rect().bottom();
// redraw area of preedit string.
update(0, cur_y - height, viewport()->width(),
(height + 1) * d->preedit_lines_);
if (preedit_string.empty()) {
last_width = false;
d->preedit_lines_ = 1;
e->accept();
return;
}
last_width = true;
// att : stores an IM attribute.
QList<QInputMethodEvent::Attribute> const & att = e->attributes();
// get attributes of input method cursor. // get attributes of input method cursor.
// cursor_pos : cursor position in preedit string. // cursor_pos : cursor position in preedit string.
size_t cursor_pos = 0; size_t cursor_pos = 0;
bool cursor_is_visible = false; bool cursor_is_visible = false;
for (int i = 0; i != att.size(); ++i) { for (auto const & attr : preedit_attr_) {
if (att.at(i).type == QInputMethodEvent::Cursor) { if (attr.type == QInputMethodEvent::Cursor) {
cursor_pos = att.at(i).start; cursor_pos = attr.start;
cursor_is_visible = att.at(i).length != 0; cursor_is_visible = attr.length != 0;
break; break;
} }
} }
size_t preedit_length = preedit_string.length(); size_t const preedit_length = preedit_string_.length();
// get position of selection in input method. // get position of selection in input method.
// FIXME: isn't there a way to do this simplier? // FIXME: isn't there a way to do this simplier?
@ -1335,12 +1189,12 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
// rLength : selected string length in IM. // rLength : selected string length in IM.
size_t rLength = 0; size_t rLength = 0;
if (cursor_pos < preedit_length) { if (cursor_pos < preedit_length) {
for (int i = 0; i != att.size(); ++i) { for (auto const & attr : preedit_attr_) {
if (att.at(i).type == QInputMethodEvent::TextFormat) { if (attr.type == QInputMethodEvent::TextFormat) {
if (att.at(i).start <= int(cursor_pos) if (attr.start <= int(cursor_pos)
&& int(cursor_pos) < att.at(i).start + att.at(i).length) { && int(cursor_pos) < attr.start + attr.length) {
rStart = att.at(i).start; rStart = attr.start;
rLength = att.at(i).length; rLength = attr.length;
if (!cursor_is_visible) if (!cursor_is_visible)
cursor_pos += rLength; cursor_pos += rLength;
break; break;
@ -1353,20 +1207,20 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
rLength = 0; rLength = 0;
} }
int const right_margin = d->buffer_view_->rightMargin(); int const right_margin = buffer_view_->rightMargin();
Painter::preedit_style ps; Painter::preedit_style ps;
// Most often there would be only one line: // Most often there would be only one line:
d->preedit_lines_ = 1; preedit_lines_ = 1;
for (size_t pos = 0; pos != preedit_length; ++pos) { for (size_t pos = 0; pos != preedit_length; ++pos) {
char_type const typed_char = preedit_string[pos]; char_type const typed_char = preedit_string_[pos];
// reset preedit string style // reset preedit string style
ps = Painter::preedit_default; ps = Painter::preedit_default;
// if we reached the right extremity of the screen, go to next line. // if we reached the right extremity of the screen, go to next line.
if (cur_x + fm.width(typed_char) > viewport()->width() - right_margin) { if (cur_x + fm.width(typed_char) > p->viewport()->width() - right_margin) {
cur_x = right_margin; cur_x = right_margin;
cur_y += height + 1; cur_y += height + 1;
++d->preedit_lines_; ++preedit_lines_;
} }
// preedit strings are displayed with dashed underline // preedit strings are displayed with dashed underline
// and partial strings are displayed white on black indicating // and partial strings are displayed white on black indicating
@ -1385,11 +1239,81 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
// draw one character and update cur_x. // draw one character and update cur_x.
cur_x += pain.preeditText(cur_x, cur_y, typed_char, font, ps); cur_x += pain.preeditText(cur_x, cur_y, typed_char, font, ps);
} }
}
// update the preedit string screen area.
update(0, cur_y - d->preedit_lines_*height, viewport()->width(), void GuiWorkArea::paintEvent(QPaintEvent * ev)
{
// LYXERR(Debug::PAINTING, "paintEvent begin: x: " << rc.x()
// << " y: " << rc.y() << " w: " << rc.width() << " h: " << rc.height());
if (d->need_resize_ || pixelRatio() != d->last_pixel_ratio_) {
d->resetScreen();
d->resizeBufferView();
}
d->last_pixel_ratio_ = pixelRatio();
GuiPainter pain(d->screenDevice(), pixelRatio());
d->buffer_view_->draw(pain, d->caret_visible_);
// The preedit text, if needed
d->paintPreeditText(pain);
// and the caret
if (d->caret_visible_)
d->caret_->draw(pain);
d->updateScreen(ev->rect());
ev->accept();
}
void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
{
LYXERR(Debug::KEY, "preeditString: " << e->preeditString()
<< " commitString: " << e->commitString());
// insert the processed text in the document (handles undo)
if (!e->commitString().isEmpty()) {
d->buffer_view_->cursor().beginUndoGroup();
d->buffer_view_->cursor().insert(qstring_to_ucs4(e->commitString()));
d->buffer_view_->updateMetrics();
d->buffer_view_->cursor().endUndoGroup();
viewport()->update();
}
// Hide the caret during the test transformation.
if (e->preeditString().isEmpty())
startBlinkingCaret();
else
stopBlinkingCaret();
if (d->preedit_string_.empty() && e->preeditString().isEmpty()) {
// Nothing to do
e->accept();
return;
}
// The preedit text and its attributes will be used in paintPreeditText
d->preedit_string_ = qstring_to_ucs4(e->preeditString());
d->preedit_attr_ = e->attributes();
// redraw area of preedit string.
int height = d->caret_->rect().height();
int cur_y = d->caret_->rect().bottom();
viewport()->update(0, cur_y - height, viewport()->width(),
(height + 1) * d->preedit_lines_); (height + 1) * d->preedit_lines_);
if (d->preedit_string_.empty()) {
d->preedit_lines_ = 1;
e->accept();
return;
}
// Don't forget to accept the event! // Don't forget to accept the event!
e->accept(); e->accept();
} }
@ -1402,12 +1326,12 @@ QVariant GuiWorkArea::inputMethodQuery(Qt::InputMethodQuery query) const
// this is the CJK-specific composition window position and // this is the CJK-specific composition window position and
// the context menu position when the menu key is pressed. // the context menu position when the menu key is pressed.
case Qt::ImMicroFocus: case Qt::ImMicroFocus:
cur_r = d->cursor_->rect(); cur_r = d->caret_->rect();
if (d->preedit_lines_ != 1) if (d->preedit_lines_ != 1)
cur_r.moveLeft(10); cur_r.moveLeft(10);
cur_r.moveBottom(cur_r.bottom() cur_r.moveBottom(cur_r.bottom()
+ cur_r.height() * (d->preedit_lines_ - 1)); + cur_r.height() * (d->preedit_lines_ - 1));
// return lower right of cursor in LyX. // return lower right of caret in LyX.
return cur_r; return cur_r;
default: default:
return QWidget::inputMethodQuery(query); return QWidget::inputMethodQuery(query);
@ -1441,12 +1365,6 @@ bool GuiWorkArea::isFullScreen() const
} }
void GuiWorkArea::scheduleRedraw()
{
d->schedule_redraw_ = true;
}
bool GuiWorkArea::inDialogMode() const bool GuiWorkArea::inDialogMode() const
{ {
return d->dialog_mode_; return d->dialog_mode_;
@ -1529,7 +1447,7 @@ QSize EmbeddedWorkArea::sizeHint () const
void EmbeddedWorkArea::disable() void EmbeddedWorkArea::disable()
{ {
stopBlinkingCursor(); stopBlinkingCaret();
if (view().currentWorkArea() != this) if (view().currentWorkArea() != this)
return; return;
// No problem if currentMainWorkArea() is 0 (setCurrentWorkArea() // No problem if currentMainWorkArea() is 0 (setCurrentWorkArea()
@ -1859,7 +1777,7 @@ void TabWorkArea::on_currentTabChanged(int i)
GuiWorkArea * wa = workArea(i); GuiWorkArea * wa = workArea(i);
LASSERT(wa, return); LASSERT(wa, return);
wa->setUpdatesEnabled(true); wa->setUpdatesEnabled(true);
wa->redraw(true); wa->scheduleRedraw(true);
wa->setFocus(); wa->setFocus();
/// ///
currentWorkAreaChanged(wa); currentWorkAreaChanged(wa);

View File

@ -27,10 +27,6 @@ class QDropEvent;
class QToolButton; class QToolButton;
class QWidget; class QWidget;
#ifdef CursorShape
#undef CursorShape
#endif
namespace lyx { namespace lyx {
class Buffer; class Buffer;
@ -64,13 +60,11 @@ public:
/// is GuiView in fullscreen mode? /// is GuiView in fullscreen mode?
bool isFullScreen() const; bool isFullScreen() const;
/// ///
void scheduleRedraw();
///
BufferView & bufferView(); BufferView & bufferView();
/// ///
BufferView const & bufferView() const; BufferView const & bufferView() const;
/// ///
void redraw(bool update_metrics); void scheduleRedraw(bool update_metrics);
/// return true if the key is part of a shortcut /// return true if the key is part of a shortcut
bool queryKeySym(KeySymbol const & key, KeyModifier mod) const; bool queryKeySym(KeySymbol const & key, KeyModifier mod) const;
@ -81,8 +75,6 @@ public:
/// ///
GuiCompleter & completer(); GuiCompleter & completer();
Qt::CursorShape cursorShape() const;
/// Return the GuiView this workArea belongs to /// Return the GuiView this workArea belongs to
GuiView const & view() const; GuiView const & view() const;
GuiView & view(); GuiView & view();
@ -95,9 +87,9 @@ public Q_SLOTS:
/// This needs to be public because it is accessed externally by GuiView. /// This needs to be public because it is accessed externally by GuiView.
void processKeySym(KeySymbol const & key, KeyModifier mod); void processKeySym(KeySymbol const & key, KeyModifier mod);
/// ///
void stopBlinkingCursor(); void stopBlinkingCaret();
/// ///
void startBlinkingCursor(); void startBlinkingCaret();
Q_SIGNALS: Q_SIGNALS:
/// ///
@ -118,8 +110,8 @@ private Q_SLOTS:
void scrollTo(int value); void scrollTo(int value);
/// timer to limit triple clicks /// timer to limit triple clicks
void doubleClickTimeout(); void doubleClickTimeout();
/// toggle the cursor's visibility /// toggle the caret's visibility
void toggleCursor(); void toggleCaret();
/// close this work area. /// close this work area.
/// Slot for Buffer::closing signal. /// Slot for Buffer::closing signal.
void close(); void close();

View File

@ -13,28 +13,19 @@
#define WORKAREA_PRIVATE_H #define WORKAREA_PRIVATE_H
#include "FuncRequest.h" #include "FuncRequest.h"
#include "LyXRC.h"
#include "support/FileName.h" #include "support/FileName.h"
#include "support/Timeout.h" #include "support/Timeout.h"
#include <QMouseEvent> #include <QMouseEvent>
#include <QImage>
#include <QPixmap>
#include <QTimer> #include <QTimer>
class QContextMenuEvent; #ifdef Q_OS_MAC
class QDragEnterEvent; /* Qt on macOS does not respect the Qt::WA_OpaquePaintEvent attribute
class QDropEvent; * and resets the widget backing store at each update. Therefore, we
class QKeyEvent; * use our own backing store in this case */
class QPaintEvent; #define LYX_BACKINGSTORE 1
class QResizeEvent; #include <QPainter>
class QToolButton;
class QWheelEvent;
class QWidget;
#ifdef CursorShape
#undef CursorShape
#endif #endif
namespace lyx { namespace lyx {
@ -44,6 +35,7 @@ class Buffer;
namespace frontend { namespace frontend {
class GuiCompleter; class GuiCompleter;
class GuiPainter;
class GuiView; class GuiView;
class GuiWorkArea; class GuiWorkArea;
@ -86,96 +78,104 @@ public:
/** /**
* Implementation of the work area (buffer view GUI) * Implementation of the work area (buffer view GUI)
*/ */
class CursorWidget; class CaretWidget;
struct GuiWorkArea::Private struct GuiWorkArea::Private
{ {
///
Private(GuiWorkArea *); Private(GuiWorkArea *);
/// update the passed area.
void update(int x, int y, int w, int h);
/// ///
void updateScreen(); ~Private();
/// ///
void resizeBufferView(); void resizeBufferView();
/// paint the cursor and store the background
void showCursor(int x, int y, int h,
bool l_shape, bool rtl, bool completable);
/// hide the cursor
void removeCursor();
/// ///
void dispatch(FuncRequest const & cmd0); void dispatch(FuncRequest const & cmd0);
/// hide the visible cursor, if it is visible /// recompute the shape and position of the caret
void hideCursor(); void updateCaretGeometry();
/// show the cursor if it is not visible /// show the caret if it is not visible
void showCursor(); void showCaret();
/// hide the caret if it is visible
void hideCaret();
/// Set the range and value of the scrollbar and connect to its valueChanged /// Set the range and value of the scrollbar and connect to its valueChanged
/// signal. /// signal.
void updateScrollbar(); void updateScrollbar();
/// Change the cursor when the mouse hovers over a clickable inset /// Change the cursor when the mouse hovers over a clickable inset
void updateCursorShape(); void updateCursorShape();
///
void setCursorShape(Qt::CursorShape shape);
bool needResize() const { void paintPreeditText(GuiPainter & pain);
return need_resize_ || p->pixelRatio() != pixel_ratio_;
void resetScreen() {
#ifdef LYX_BACKINGSTORE
int const pr = p->pixelRatio();
screen_ = QImage(static_cast<int>(pr * p->viewport()->width()),
static_cast<int>(pr * p->viewport()->height()),
QImage::Format_ARGB32_Premultiplied);
# if QT_VERSION >= 0x050000
screen_.setDevicePixelRatio(pr);
# endif
#endif
} }
void resetScreen() QPaintDevice * screenDevice() {
{ #ifdef LYX_BACKINGSTORE
delete screen_; return &screen_;
pixel_ratio_ = p->pixelRatio(); #else
if (lyxrc.use_qimage) { return p->viewport();
QImage *x =
new QImage(static_cast<int>(pixel_ratio_ * p->viewport()->width()),
static_cast<int>(pixel_ratio_ * p->viewport()->height()),
QImage::Format_ARGB32_Premultiplied);
#if QT_VERSION >= 0x050000
x->setDevicePixelRatio(pixel_ratio_);
#endif #endif
screen_ = x;
} else {
QPixmap *x =
new QPixmap(static_cast<int>(pixel_ratio_ * p->viewport()->width()),
static_cast<int>(pixel_ratio_ * p->viewport()->height()));
#if QT_VERSION >= 0x050000
x->setDevicePixelRatio(pixel_ratio_);
#endif
screen_ = x;
}
} }
#ifdef LYX_BACKINGSTORE
void updateScreen(QRectF const & rc) {
QPainter qpain(p->viewport());
double const pr = p->pixelRatio();
QRectF const rcs = QRectF(rc.x() * pr, rc.y() * pr,
rc.width() * pr, rc.height() * pr);
qpain.drawImage(rc, screen_, rcs);
}
#else
void updateScreen(QRectF const & ) {}
#endif
/// ///
GuiWorkArea * p; GuiWorkArea * p;
/// ///
QPaintDevice * screen_;
///
BufferView * buffer_view_; BufferView * buffer_view_;
/// ///
GuiView * lyx_view_; GuiView * lyx_view_;
/// is the cursor currently displayed
bool cursor_visible_;
#ifdef LYX_BACKINGSTORE
/// ///
QTimer cursor_timeout_; QImage screen_;
#endif
///
CaretWidget * caret_;
/// is the caret currently displayed
bool caret_visible_;
///
QTimer caret_timeout_;
/// ///
SyntheticMouseEvent synthetic_mouse_event_; SyntheticMouseEvent synthetic_mouse_event_;
/// ///
DoubleClick dc_event_; DoubleClick dc_event_;
///
CursorWidget * cursor_;
/// ///
bool need_resize_; bool need_resize_;
///
bool schedule_redraw_; /// the current preedit text of the input method
/// docstring preedit_string_;
/// Number of lines used by preedit text
int preedit_lines_; int preedit_lines_;
/// the attributes of the preedit text
QList<QInputMethodEvent::Attribute> preedit_attr_;
/// Ratio between physical pixels and device-independent pixels /// Ratio between physical pixels and device-independent pixels
/// We save the last used value to detect changes of the /// We save the last used value to detect changes of the
/// current pixel_ratio of the viewport. /// current pixel_ratio of the viewport.
double pixel_ratio_; double last_pixel_ratio_;
/// ///
GuiCompleter * completer_; GuiCompleter * completer_;

File diff suppressed because it is too large Load Diff

View File

@ -6,172 +6,15 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>500</width> <width>569</width>
<height>367</height> <height>367</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string/> <string/>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0"> <item row="0" column="0">
<widget class="QLabel" name="allPakcagesLA">
<property name="text">
<string>All packages:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="allPackagesAutoPB">
<property name="text">
<string>Load A&amp;utomatically</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="allPackagesAlwaysPB">
<property name="text">
<string>Load Alwa&amp;ys</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="allPackagesNotPB">
<property name="text">
<string>Do &amp;Not Load</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="MathIndentCB">
<property name="toolTip">
<string>Indent displayed formulas instead of centering</string>
</property>
<property name="text">
<string>Indent &amp;Formulas</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="MathIndentCO">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Size of the indentation</string>
</property>
</widget>
</item>
<item row="2" column="2" colspan="2">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>234</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="MathIndentLE">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string/>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="lyx::frontend::LengthCombo" name="MathIndentLengthCO">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string/>
</property>
</widget>
</item>
<item row="3" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>153</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="0">
<widget class="QLabel" name="MathNumberingPosL">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>115</width>
<height>18</height>
</size>
</property>
<property name="text">
<string>Formula numbering side:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="MathNumberingPosCO">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Side where formulas are numbered</string>
</property>
</widget>
</item>
<item row="4" column="2" colspan="2">
<spacer name="horizontalSpacer_1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>234</width>
<height>17</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="4">
<widget class="QTableWidget" name="packagesTW"> <widget class="QTableWidget" name="packagesTW">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
@ -179,6 +22,9 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="columnCount"> <property name="columnCount">
<number>4</number> <number>4</number>
</property> </property>
@ -194,6 +40,171 @@
<column/> <column/>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="allPakcagesLA">
<property name="text">
<string>All packages:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="allPackagesAutoPB">
<property name="text">
<string>Load A&amp;utomatically</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="allPackagesAlwaysPB">
<property name="text">
<string>Load Alwa&amp;ys</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="allPackagesNotPB">
<property name="text">
<string>Do &amp;Not Load</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="MathIndentCB">
<property name="toolTip">
<string>Indent displayed formulas instead of centering</string>
</property>
<property name="text">
<string>Indent &amp;Formulas</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="MathIndentCO">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Size of the indentation</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="2">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>234</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="MathIndentLE">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string/>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="lyx::frontend::LengthCombo" name="MathIndentLengthCO">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string/>
</property>
</widget>
</item>
<item row="2" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>153</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="MathNumberingPosL">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>115</width>
<height>18</height>
</size>
</property>
<property name="text">
<string>Formula numbering side:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="MathNumberingPosCO">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Side where formulas are numbered</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>234</width>
<height>17</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout> </layout>
</widget> </widget>
<customwidgets> <customwidgets>

View File

@ -1,7 +1,8 @@
<ui version="4.0" > <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PreambleUi</class> <class>PreambleUi</class>
<widget class="QWidget" name="PreambleUi" > <widget class="QWidget" name="PreambleUi">
<property name="geometry" > <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
@ -9,19 +10,38 @@
<height>278</height> <height>278</height>
</rect> </rect>
</property> </property>
<property name="windowTitle" > <property name="windowTitle">
<string/> <string/>
</property> </property>
<layout class="QGridLayout" > <layout class="QGridLayout">
<property name="margin" > <property name="leftMargin">
<number>11</number> <number>11</number>
</property> </property>
<property name="spacing" > <property name="topMargin">
<number>11</number>
</property>
<property name="rightMargin">
<number>11</number>
</property>
<property name="bottomMargin">
<number>11</number>
</property>
<property name="spacing">
<number>6</number> <number>6</number>
</property> </property>
<item row="0" column="0" > <item row="1" column="0">
<widget class="QTextEdit" name="preambleTE" > <widget class="QLineEdit" name="findLE"/>
<property name="acceptRichText" > </item>
<item row="1" column="1">
<widget class="QPushButton" name="findButtonPB">
<property name="text">
<string>Find</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QTextEdit" name="preambleTE">
<property name="acceptRichText">
<bool>false</bool> <bool>false</bool>
</property> </property>
</widget> </widget>
@ -29,7 +49,7 @@
</layout> </layout>
</widget> </widget>
<includes> <includes>
<include location="local" >qt_i18n.h</include> <include location="local">qt_i18n.h</include>
</includes> </includes>
<resources/> <resources/>
<connections/> <connections/>

View File

@ -249,6 +249,7 @@ docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams)
ParagraphList::const_iterator it = buffer.paragraphs().begin(); ParagraphList::const_iterator it = buffer.paragraphs().begin();
ParagraphList::const_iterator end = buffer.paragraphs().end(); ParagraphList::const_iterator end = buffer.paragraphs().end();
bool is_literal = false;
for (; it != end; ++it) { for (; it != end; ++it) {
if (it->insetList().empty()) if (it->insetList().empty())
continue; continue;
@ -274,11 +275,14 @@ docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams)
if (wx > w) { if (wx > w) {
w = wx; w = wx;
lbl = label; lbl = label;
is_literal = (bitem->getParam("literal") == "true");
} }
} }
if (!lbl.empty()) { if (!lbl.empty()) {
InsetCommandParams p(BIBITEM_CODE); InsetCommandParams p(BIBITEM_CODE);
if (is_literal)
p["literal"] = from_ascii("true");
return p.prepareCommand(runparams, lbl, ParamInfo::HANDLING_LATEXIFY); return p.prepareCommand(runparams, lbl, ParamInfo::HANDLING_LATEXIFY);
} }

View File

@ -59,6 +59,12 @@ InsetCitation::~InsetCitation()
} }
// May well be over-ridden when session settings are loaded
// in GuiCitation. Unfortunately, that will not happen until
// such a dialog is created.
bool InsetCitation::last_literal = true;
ParamInfo const & InsetCitation::findInfo(string const & /* cmdName */) ParamInfo const & InsetCitation::findInfo(string const & /* cmdName */)
{ {
static ParamInfo param_info_; static ParamInfo param_info_;

View File

@ -82,10 +82,14 @@ public:
static bool isCompatibleCommand(std::string const &); static bool isCompatibleCommand(std::string const &);
//@} //@}
/// ///
void redoLabel() { cache.recalculate = true; }
///
CitationStyle getCitationStyle(BufferParams const & bp, std::string const & input, CitationStyle getCitationStyle(BufferParams const & bp, std::string const & input,
std::vector<CitationStyle> const & valid_styles) const; std::vector<CitationStyle> const & valid_styles) const;
/// ///
std::map<docstring, docstring> getQualifiedLists(docstring const p) const; std::map<docstring, docstring> getQualifiedLists(docstring const p) const;
///
static bool last_literal;
private: private:
/// tries to make a pretty label and makes a basic one if not /// tries to make a pretty label and makes a basic one if not

View File

@ -1150,7 +1150,8 @@ void unifyGraphicsGroups(Buffer & b, string const & argument)
InsetGraphicsParams params; InsetGraphicsParams params;
InsetGraphics::string2params(argument, b, params); InsetGraphics::string2params(argument, b, params);
b.undo().beginUndoGroup(); // This handles undo groups automagically
UndoGroupHelper ugh(&b);
Inset & inset = b.inset(); Inset & inset = b.inset();
InsetIterator it = inset_iterator_begin(inset); InsetIterator it = inset_iterator_begin(inset);
InsetIterator const end = inset_iterator_end(inset); InsetIterator const end = inset_iterator_end(inset);
@ -1165,7 +1166,6 @@ void unifyGraphicsGroups(Buffer & b, string const & argument)
} }
} }
} }
b.undo().endUndoGroup();
} }

View File

@ -97,12 +97,12 @@ void InsetLabel::updateLabelAndRefs(docstring const & new_label,
if (label == old_label) if (label == old_label)
return; return;
buffer().undo().beginUndoGroup(); // This handles undo groups automagically
UndoGroupHelper ugh(&buffer());
if (cursor) if (cursor)
cursor->recordUndo(); cursor->recordUndo();
setParam("name", label); setParam("name", label);
updateReferences(old_label, label); updateReferences(old_label, label);
buffer().undo().endUndoGroup();
} }

View File

@ -157,6 +157,7 @@ void RenderGraphic::metrics(MetricsInfo & mi, Dimension & dim) const
dim.des = 0; dim.des = 0;
int font_width = 0; int font_width = 0;
int font_height = 0;
FontInfo msgFont(mi.base.font); FontInfo msgFont(mi.base.font);
msgFont.setFamily(SANS_FAMILY); msgFont.setFamily(SANS_FAMILY);
@ -166,6 +167,7 @@ void RenderGraphic::metrics(MetricsInfo & mi, Dimension & dim) const
if (!justname.empty()) { if (!justname.empty()) {
msgFont.setSize(FONT_SIZE_FOOTNOTE); msgFont.setSize(FONT_SIZE_FOOTNOTE);
font_width = theFontMetrics(msgFont).width(justname); font_width = theFontMetrics(msgFont).width(justname);
font_height = theFontMetrics(msgFont).maxHeight();
} }
docstring const msg = statusMessage(params_, loader_.status()); docstring const msg = statusMessage(params_, loader_.status());
@ -173,9 +175,12 @@ void RenderGraphic::metrics(MetricsInfo & mi, Dimension & dim) const
msgFont.setSize(FONT_SIZE_TINY); msgFont.setSize(FONT_SIZE_TINY);
font_width = max(font_width, font_width = max(font_width,
theFontMetrics(msgFont).width(msg)); theFontMetrics(msgFont).width(msg));
font_height += theFontMetrics(msgFont).maxAscent();
dim.des = theFontMetrics(msgFont).maxDescent();
} }
dim.wid = max(50, font_width + 15); dim.wid = max(50, font_width + 15);
dim.asc = max(50, font_height + 15);
dim_ = dim; dim_ = dim;
} }

Some files were not shown because too many files have changed in this diff Show More