Skip to content

Saturday, 10 August 2019

The sprint has officially ended yesterday and most of the participants have already left, except me, Ivan, Wolthera and Jouni. Well I would have also left as planned but I read my flight timings wrong and it would leave after 3 hours of what I thought the departure time was.

Friday, 9 August 2019

Previously: 1st GSoC post 2nd GSoC post 3rd GSoC post 4th GSoC post In this GSoC entry I’ll mention two things implemented since the last blog post: syncing of scaling and NumLock settings. Aside from that, I’ll reflect on syncing of locally-installed files. Even thought I thought scaling would require changes on the SDDM side...... Continue Reading →

So far, most of my blog postings that appeared on Planet KDE were release announcements for KBibTeX. Still, I had always planned to write more about what happens on the development side of KBibTeX. Well, here comes my first try to shed light on KBibTeX's internal working …

Active development of KBibTeX happens in its master branch. There are other branches created from time to time, mostly for bug fixing, i. e. allowing bug reporters to compile and test a bug fix before before the change is merged into master or a release branch. Speaking of release branches, those get forked from master every one to three years. At the time of writing, the most recent release branch is kbibtex/0.9. Actual releases, including alpha or beta releases, are tagged on those release branches.

KBibTeX is developed on Linux; personally I use the master branch on Gentoo Linux and Arch Linux. KBibTeX compiles and runs on Windows with the help of Craft (master better than kbibtex/0.9). It is on my mental TODO list to configure a free Windows-based continuous integration service to build binary packages and installers for Windows; suggestions and support are welcome. Craft supports macOS, too, to some extend as well, so I gave KBibTeX a shot on this operating system (I happen to have access to an old Mac from time to time). Running Craft and installing packages caused some trouble, as macOS is the least tested platform for Craft. Also, it seems to be more difficult to find documentation on how to solve compilation or linking problems on macOS than it is for Windows (let alone Linux). However, with the help of the residents in #kde-craft and related IRC channels, I was eventually able to start compiling KBibTeX on macOS (big thanks!).

The main issue that came up when crafting KBibTeX on macOS was the problem of linking against ICU (International Components for Unicode). This library is shipped on macOS as it is used in many other projects, but seemingly even if you install Xcode, you don't get any headers or other development files. Installing a different ICU version via Craft doesn't seem to work either. However, I am no macOS expert, so I may have gotten the details wrong …

Discussing in Craft's IRC channel how to get KBibTeX installed on macOS despite its dependency on ICU, I got asked why KBibTeX needs to use ICU in the first place, given that Qt ships QTextCodec which covers most text encoding needs. My particular need is to transliterate a given Unicode text like ‘äåツ’ into a 7-bit ASCII representation. This is used among others to rewrite identifiers for BibTeX entries from whatever the user wrote or an imported BibTeX file contained to an as close as possible 7-bit ASCII representation (which is usually the lowest common denominator supported on all systems) in order to reduce issues if the file is fed into an ancient bibtex or shared with people using a different encoding or keyboard layout.

Such a transliteration is also useful in other scenarios such as if filenames are supposed to be based on a person's name but still must be transcribed into ASCII to be accessible on any filesystem and for any user irrespective of keyboard layout. For example, if a filename needs to have some resemblance the Scandinavian name ‘Ångström’, the name's transliteration could be ‘Angstrom’, thus a file could be named Angstrom.txt.

So, if ICU is not available, what are the alternatives? Before I adopted ICU for the transliteration task, I had used iconv. Now, my first plan to avoid hard-depending on ICU was to test for both ICU and iconv during the configuration phase (i. e. when cmake runs) and use ICU if available and fall back to iconv if no ICU was available. Depending on the chosen alternative, paths and defines (to enable or disable specific code via #ifdefs) were set.
See commit 2726f14ee9afd525c4b4998c2497ca34d30d4d9f for the implementation.

However, using iconv has some disadvantages which motivated my original move to ICU:

  1. There are different iconv implementations out there and not all support transliteration.
  2. The result of a transliteration may depend on the current locale. For example, ‘ä’ may get transliterated to either ‘a’ or ‘ae’.
  3. Typical iconv implementations know less Unicode symbols than ICU. Results are acceptable for European or Latin-based scripts, but for everything else you far too often get ‘?’ back.

Is there a third option? Actually, yes. Qt's Unicode code supports only the first 216 symbols anyway, so it is technically feasible to maintain a mapping from Unicode character (essentially a number between 0 and 65535) to a short ASCII string like AE for ‘Æ’ (0x00C6). This mapping can be built offline with the help of a small program that does link against ICU, queries this library for a transliteration for every Unicode code point from 0 to 65535, and prints out a C/C++ source code fragment containing the mapping (almost like in the good old days with X PixMaps). This source code fragment can be included into KBibTeX to enable transliteration without requiring/depending on either ICU or iconv on the machines where KBibTeX is compiled or run. Disadvantages include the need to drag along this mapping as well as to updated it from time to time in order to keep up with updates in ICU's own transliteration mappings.
See commit 82e15e3e2856317bde0471836143e6971ef260a9 where the mapping got introduced as the third option.

The solution I eventually settled with is to still test for ICU during the configuration phase and make use of it in KBibTeX as I did before. However, in case no ICU is available, the offline-generated mapping will be used to offer essentially the same functionality. Switching between both alternatives is a compile-time thing, both code paths are separated by #ifdefs.

Support for iconv has been dropped as it became the least complete solution (see commit 47485312293de32595146637c96784f83f01111e).

Now, how does this generated mapping look like? In order to minimize the data structure's size I came up with the following approach: First, there is a string called const char *unidecode_text that contains any occurring plain ASCII representation once, for example only one single a that can be used for ‘a’, ‘ä’, ‘å’, etc. This string is about 28800 characters long for 65536 Unicode code points where a code point's ASCII representation may be several characters long. So, quite efficient.

Second, there is an array const unsigned int unidecode_pos[] that holds a number for every of the 65536 Unicode code points. Each number contains both a position and a length telling which substring to extract from unidecode_text to get the ASCII representation. As the observed ASCII representations' lengths never exceed 31, the array's unsigned ints contain the representations' lengths in their lower (least significant) five bits, the remaining more significant bits contain the positions. For example, to get the ASCII representation for ‘Ä’, use the following approach:

const char16_t unicode = 0x00C4; ///< 'A' with two dots above (diaeresis)
const int pos = unidecode_pos[unicode] >> 5;
const int len = unidecode_pos[unicode] & 31;
const char *ascii = strndup(unidecode_text + pos, len);

If you want to create a QString object, use this instead of the last line above:

const QString ascii = QString::fromLatin1(unidecode_text + pos, len);

If you would go through this code step-by-step with a debugger, you would see that unidecode_pos[unicode] has value 876481 (this value may change if the generated source code changes). Thus, pos becomes 27390 and len becomes 1. Indeed and not surprisingly, in unidecode_text at this position is the character A. BTW, value 876481 is not just used for ‘Ä’, but also for ‘À’ or ‘Â’, for example.

Above solution can be easily adjusted to work with plain C99 or modern C++. It is in no way specific to Qt or KDE, so it should be possible to use it as a potential solution to musl (a libc implementation) to implement a //TRANSLIT feature in their iconv implementation (I have not checked their code if that is possible at all).



comment count unavailable comments

Thursday, 8 August 2019

…and I’ve made a new wallpaper!

Yes, finally i’m back on my favourite application, Inkscape.

rect12372

Hope this is a cool presentation

I called this wallpaper Mountain, because … well, there are mountains with a sun made with the KDE Neon logo. hope you like it 🙂

You can find it HERE

See you soon with other wallpapers …

 

 

Monday, 5 August 2019

With any new version of the Qt toolkit comes some clean-up of its APIs to keep it clean, consistent, and future-proof. Part of this clean-up is to rename API functions to make it more clear what they actually do.

Starting with Qt 5.11, the QFontMetrics::width() function was deprecated. You could still compile code that uses this function, but since it is marked obsolete, you were encouraged to port away from it.

So what is unclear or not consistent about it? The function name and signature suggest that you can retrieve the width of a text string (or single character) taking into account the metrics of a specific font. Such metrics are needed to create widget layouts that automatically adapt to user specified fonts or different system display DPIs.

Reading the API description, the result is actually not the width. The graphics shown at https://doc.qt.io/qt-5/qfontmetrics-obsolete.html#width illustrates that there is a difference between the horizontal advance, i.e. the number of pixels from one character to the next character, and the bounding rectangle width, which is needed to encompass all pixels including so called bearings that can overlap the next or the previous character.

Since it was not clear from the confusingly named function QFontMetrics::width() that it actually returned the horizontal advance, instead of the bounding width, this method is now obsolete. You must port to either QFontMetrics::horizontalAdvance() or QFontMetrics::boundingRect().width().

Please make sure you are aware of the difference, and do not port blindly. I am pretty sure that in most cases QFontMetrics::boundingRect() is what you want, unless you are writing custom text shaping/layouting code. Using the wrong function can cause clipped text or text that suddenly wraps to the next line despite calculating the width that it needs.

Sunday, 4 August 2019

Overview

One of the tasks for GSoC 2019, was adding multiple datasets to calendar activities, but along with the task I also planned on adding another inprovement to the activity. The activity initially used hardcoded questions and answesr regarding calenders. The dataset for which looked like

data: [
{
"navigationBarVisible" : true,
"minimumDate": "2018-01-01",
"maximumDate": "2018-12-31",
"visibleMonth": 1,
"visibleYear": 2018,
"mode": "findMonthOnly",
"questionsExplicitlyGiven": true,
"questionAnswers": [
{
"question": qsTr("Find the month starting a Thursday and having 28 days"),
"answer": {"month": [1]}
},
{
"question": qsTr("Find a month starting a Monday and having 31 days"),
"answer": {"month": [0, 9]}
},
{
"question": qsTr("Find the month between June and August"),
"answer": {"month": [6]}
},
{
"question": qsTr("Find a month starting a Saturday"),
"answer": {"month": [8, 11]}
},
{
"question": qsTr("Find a month having 30 days"),
"answer": {"month": [3, 5, 8, 10]}
}
]
}, ... and more levels so on
]

So I planned on creating an algorithm that could generate some template questions and answers. The activity has four type of questions depending in the mode. The available modes are

      // findMonthOnly --> For questions based on finding month only.
// findYearMonthDay --> For questions based on finding year, month and day.
// findDayOfWeek --> For questions based on finding day of week only.
// findDay --> For questions based on finding day of a given month and year.

So, I the algorithm should generate different questions for each type.

Function to generate date in Range

The first task is to create a function that would generate a random date within the given range i.e minDate and maxDate.

function generateRandomYearMonthDay(minimumDate, maximumDate) {
var minYear = Number(minimumDate.slice(0, 4))
var maxYear = Number(maximumDate.slice(0, 4))
var minMonth = Number(minimumDate.slice(5, 7))
var maxMonth = Number(maximumDate.slice(5, 7))
var minDate = Number(minimumDate.slice(8, 10))
var currentYear = minYear + Math.floor(Math.random() * Math.floor((maxYear - minYear + 1)))
var currentMonth = minMonth + Math.floor(Math.random() * Math.floor((maxMonth - minMonth + 1)))
var currentDate
daysInMonths[1] = (isLeapYear(currentYear)) ? 29 : 28;
currentDate = minDate + Math.floor(Math.random() * Math.floor((daysInMonths[currentMonth - 1] - minDate + 1)))
return { year: currentYear, month: currentMonth - 1, day: currentDate }
}

Function to add offset

There are some questions which require the user to find a date, a given number of days ahead of the current date. So I created a function to calculate that date.

function addOffsetToCurrentDate(currentDate) {
var maxOffset = currentLevelConfig.questionAnswers.maxOffset
var offset = Math.floor(maxOffset / 2) + Math.floor(Math.random() * Math.floor(maxOffset))
daysInMonths[1] = (isLeapYear(currentDate.year)) ? 29 : 28;
offset += currentDate.day
var answerDate = 1;
var answerMonth = currentDate.month
var answerYear = currentDate.year
while(offset > 0) {
if(offset - daysInMonths[answerMonth] > 0) {
offset -= daysInMonths[answerMonth]
answerMonth++;
} else {
answerDate = offset;
offset = 0
}
if(answerMonth > 12) {
answerYear++;
daysInMonths[1] = (isLeapYear(answerYear)) ? 29 : 28;
answerMonth = 0;
}
}
return { year: answerYear, month: answerMonth, day: answerDate, offset: offset }
}

Function to generate template questions

Now there has to be a function that would return the correct question text template as per the mode of the question. So I created a function for that.

function getTemplateQuestionText(mode, date) {
var questionText
if(mode == "findDayOfWeek") {
questionText = qsTr("What day of the week is on %1?").arg(getDateInLongFormat(date))
} else if(mode == "findDay") {
questionText = qsTr("Select day %1?").arg(date.day)
} else if(mode == "findMonthOnly") {
questionText = qsTr("Find month number %1").arg(date.month + 1)
} else {
if(date.offset) {
//: The second argument represents the given date in complete format(with complete month name) and the first argument represents the difference in days between given date and answer date.
questionText = qsTr("Find the date %1 days after %2").arg(date.offset).arg(getDateInLongFormat(date))
} else
//: The argument represents the answer date in complete format(with complete month name)
questionText = qsTr("Find the date %1").arg(getDateInLongFormat(date))
}
return questionText
}

Function to set question and answer values

Finally I created a function that would set the correct values of the question and answer variables as per the selected mode.

 if(!currentLevelConfig.questionsExplicitlyGiven) {
var randomDate = generateRandomYearMonthDay(currentLevelConfig.minimumDate, currentLevelConfig.maximumDate)
items.score.currentSubLevel = currentSubLevel
if(currentLevelConfig.mode == "findDayOfWeek") {
var selectedDate = new Date(randomDate.year, randomDate.month - 1, randomDate.day)
correctAnswer.dayOfWeek = Number(selectedDate.getDay())
} else if(currentLevelConfig.mode == "findYearMonthDay" && currentLevelConfig.questionAnswers.maxOffset) {
correctAnswer = addOffsetToCurrentDate(randomDate)
randomDate.offset = correctAnswer.offset
} else {
correctAnswer = randomDate
}
items.questionItem.text = getTemplateQuestionText(currentLevelConfig.mode, randomDate)
}

The part of code is executed only if the questions are not explicitly given.

Dataset contents for template questions

If the dataset creater wants to use template function then he can define then like

{
"navigationBarVisible" : true,
"minimumDate": "2018-01-01",
"maximumDate": "2019-12-31",
"visibleMonth": 10,
"visibleYear": 2018,
"mode": "findYearMonthDay",
"questionsExplicitlyGiven": false,
"questionAnswers": {
"length": 5,
"maxOffset": 90
}
},

where the variable length defines the length of questionSet or the number of questions.

![](https://i.imgur.com/yXIstf1.jpg “digiKam 6.2.0-01) Dear digiKam fans and users, We received a lot of excellent user feedback after publishing the second digiKam 6 release in April 2019. We are now proud to briefly announce the new digiKam 6.2.0, a maintenance version which consolidates this feedback and acts as an important phase of this 2-year-old project. New Cameras Supported by Raw Files Engine digiKam tries to fully support all digital camera formats.

Friday, 2 August 2019

Sprint ahoy 🔗

Kuntal Majumder hellozee 15:28 +00:00
RSS
Well, I did manage to get some work done during the start of the week cause after that it was just dripping nose and back to back headaches along with a sore throat for around the next 3 days, and I also had to prepare for Krita sprints happening next week.

Thursday, 1 August 2019

When interacting with other users of KDE Connect, I often notice something funny. People will often talk about how nice it is that they can control their computer from their phone (using the media controls, the mousepad plugin, or several of the others). For me, this has always been a secondary benefit. I use KDE Connect’s presentation plugin for all of my presentations but my primary goal has always been to be able to control my phone from my computer. I hate the phone keyboard, I hate the tiny screen, and I hate having to pull the thing out of my pocket.

On a daily basis, the number 1 thing I need to do with my phone is send or read SMS. In the United States, SMS is the de facto default communication system. In Europe, I basically assume that anyone I want to communicate with uses WhatsApp. In the US, with one friend I use WhatsApp, with another one friend I use Telegram, and with my family and other friends I use SMS. (Many people use Facebook Messenger but that is still not as widespread).

Those who have been very carefully following the KDE Connect channels might already know that we have been working on a desktop application which uses KDE Connect to load SMS conversation history and send SMS using the phone. (I have been keeping this under wraps because I know it is our #1 requested feature and I don’t want to tease anyone with a stream of “Oh yes, it’s almost there” half-promises)

The SMS app started March 2018 at the previous KDE Connect sprint. I arrived in Barcelona with a half-written contacts synchronization plugin and the goal to never touch my phone again. In only a few days, we had the contacts plugin in its current form and the skeleton of an SMS app (based on Qt’s QML chat app tutorial). It could read the display names and avatars from the synchronized contacts and you could use the compose message box to send SMS. There was no message history yet, just some statically-created items in the QML, but everything starts somewhere!

2018-03-26 KDE Connect v0-0.jpg
KDE Connect SMS v0.0

Around May, Aleix Pol and I were talking about what the interface should look like. We agreed that it should be very “normal”, like every other chat app, so I came up with this fabulous drawing.

1564053347781.jpg
Special thanks to PhotoScan for only being able to export photos with a watermark

The history of the SMS app has more details than we need for this post. Along the way, the KDE Connect Android app was updated with many content resolvers (and many StackOverflow references) to handle getting the SMS (and MMS) history. Several GUI elements have been “borrowed” from Kaidan. High on my soon-to-do list is move the Kaidan GUI elements which could be used by any other project looking to make a chat interface.

I am very happy with the current version of the app. I use it regularly and I find it very useful. Though it only has a few features, I have focused on fewer, more-stable features for the initial release. It can:

  • Show a list of conversation currently existing on the phone
  • Show conversation history
  • Send and display SMS
  • Display (not send) plain-text MMS including group messages
  • Understand non-text MMS
  • Update in real-time as more messages are received

I have left several thing for future releases:

  • Start a new conversation
    • I consider this a less-common usecase than replying to an existing conversation, so I focused on other things
  • Show MMS attachments
    • This requires upgrading the Android interface to read arbritrary attachments and upgrading the GUI to do something with those (like display pictures and offer downloads for everything else)
  • Send MMS
    • The current SMS-sending interface is very basic, so it will probably be significantly modified or even replaced.

Here is the current version of the SMS app:

2019-07-25 KDE Connect SMS v1.0

And the corresponding conversation on the phone:

Screenshot_20190725-135536

The SMS app now builds by default when you build KDE Connect so it will be officially released with the next release of KDE Connect. Hopefully I have time to iron out one or two more bugs before then!

Tuesday, 30 July 2019

Hello everyone!

In the previous post I mentioned that Cantor now handles embedded mathematical expressions inside of Markdown, like $...$ and $$...$$ in accordance with the Markdown syntax.

In the past Cantor for a long time didn’t have any support for Markdown and only have simple text entry type for comment purposes. Markdown entry type was added only in 2018 by kqwyf. Internally, this was realized by using the Discount library, which converts markdown syntax to the to html code which is then passed to Qt for final the rendering (Qt supports limited set of the html syntax).

Discount library actually supports integration with LaTeX: text inside LaTeX expressions like $$...$$, \(...\), \[...]\ is passed to the output html string without modifications (except html escaping).

As you see Discount doesn't support embedded mathematics with single delimiter $...$ that is used in Jupyter very frequently. Of course, for my Jupiter integration projects ignoring this type of statements was not an option. I decided to report this issue in Discount bug tracker because all the other options solve this problem purely in Cantor had other problems.

Fortunately, the author of Discount reacted very soon (thanks to him for that) and suggested code changes for supporting the single-delimited math. Unfortunately, the changes didn't get into master branch yet. To proceed further in Cantor I decided to copy required Discount’s code having all the relevant changed into Cantor’s repository as a third party library.

Independent of the support for the single-delimiter mathematics, there is a big problem with the embedded mathematical expressions - you need to somehow find these mathematical statements in output html string. In the initial implementation I simply searched for $$ in the result string but this could lead to "search collisions".

The dollar sign could be inside of a Markdown code block or inside of a quote block. Here, the dollar signs shouldn't treated as part of the embedded mathematics. After some further testing of couple of other implementations on Cantor sidethe conclusion was obvios - the identification and labeling of positions of embedded mathematics in the html string, produced by Discount, should be done directly inside Discount itself.

At this moment, the version of Discount added to Cantor’s repository had two additional functional fixes on top of the officially released version of this library. First, Discount copies all LaTeX expressions during the processing of markdown syntax to a special string list, which is then used by Cantor to search for LaTeX code. Second, a useful change was to add an ASCII non-text symbol to every math expression. This symbol is used as a search key which greatly reduces the likelihood for a string collision, still theoretically possible, though.

For example, if Discount will find (according Markdown syntax) math expression $\Gamma$, then it will write the additional symbol and the expression iin the output html string will be $<symbol>\Gamma$ and Cantor will search exactly this text.

I think, that's all.  Maybe this doesn’t look like a complex problem but solving this problem was a task that took the most time and it took me two months to fix it. So, I think the problem and its solution deserved a separate blog post.

At this moment, what I called "maximum plan" (I have mentioned this concep in this post) of the Jupyter support in Cantor is mostly finished. So, in the next post I plan to show how Cantor now handles test notebooks and what I’ll plan to do next.