Skip to content

Sunday, 13 April 2025

Welcome to a new issue of "This Week in KDE Apps"! Every week we cover as much as possible of what's happening in the world of KDE apps.

As Carl is still in vacation, this issue is only partially complete.

System Apps

Dolphin Manage your files

The Dolphin search integration has been rewritten from scratch. Notably, users can now switch the search tool between a simple search algorithm and one using file indexing and offering advanced search options. This way users are no longer forced to use the file index whenever it is available and can instead search in a slower but more reliable manner.

The overall user interface design is much improved with better clarity about what is currently being searched and which parameters can be changed. It was designed in a collaborative effort by Kristen McWilliam, Jin Liu, Andy Betts, Tagwerk, Felix Ernst, and a few others. (Felix Ernst, 25.08.0. Link)

The "Show in Groups" action was moved from the "View" menu to the "Sort By" menu. (Nate Graham, 25.08.0. Link)

The "Change View Mode" button which was recently added to Dolphin's default tool bar configuration is now icon-only by default (just like we had intended). (Akseli Lahtinen, 25.08.0. Link)

In the Trash context menu the "Properties" action is now once again in the last position just like in all the other Dolphin view context menus. This now-fixed inconsistency was an unintended side-effect of us moving the "Delete" action last to make it less likely to click it by accident when aiming at "Restore". (Kai Uwe Broulik, 25.08.0. Link)

Dolphin will now hide the background of the navigation bar when it's outside of the toolbar. (Akseli Lahtinen, 25.08.0. Link)

Other

Various improvements were made for the KDE Open and Save dialog:

  • People using single-click selection can now click on checkboxes to select individual items in multi-selection dialogs. This works similarly to how it does in Dolphin. (Akseli Lahtinen, KIO 6.14. Link)
  • Open and Save dialogs now allow quickly filtering through files by filename when pressing CTRL+I or Backslash key, like in Dolphin. (Akseli Lahtinen, KIO 6.14. Link)

…And Everything Else

This blog only covers the tip of the iceberg! If you’re hungry for more, check out Nate's blog about Plasma and be sure not to miss his This Week in Plasma series, where every Saturday he covers all the work being put into KDE's Plasma desktop environment.

For a complete overview of what's going on, visit KDE's Planet, where you can find all KDE news unfiltered directly from our contributors.

Get Involved

The KDE organization has become important in the world, and your time and contributions have helped us get there. As we grow, we're going to need your support for KDE to become sustainable.

You can help KDE by becoming an active community member and getting involved. Each contributor makes a huge difference in KDE — you are not a number or a cog in a machine! You don’t have to be a programmer either. There are many things you can do: you can help hunt and confirm bugs, even maybe solve them; contribute designs for wallpapers, web pages, icons and app interfaces; translate messages and menu items into your own language; promote KDE in your local community; and a ton more things.

You can also help us by donating. Any monetary contribution, however small, will help us cover operational costs, salaries, travel expenses for contributors and in general just keep KDE bringing Free Software to the world.

To get your application mentioned here, please ping us in invent or in Matrix.

Finishing Up

Kalah

Hey everyone, It’s me again, back with the final update for this year’s Season of KDE. So, turns out things don’t really go as planned and it took me some extra time to bring it over the line.

Since my last post, I wrote the tests for the Kalah game, the associated TUI, a greedy move selection and benchmarked Oware and Bohnenspiel. My mid-sem exams happened, in between, and delayed me by 2 weeks.

Dear fans of music & open source music players,
in preparation of the upcoming Amarok 3.3 release, a beta release (3.2.81) has been prepared.

As shown in the ChangeLog, the changes are mostly technical: Qt5 support is removed, and Amarok 3.3 beta is compatible with Qt6/KF6 only. Additionally, a database scheme update (first such since 2012) fixes encoding and date related bugs.

Please note that due to the database update, downgrading from 3.3 beta is not directly possible, and returning to pre-3.3 versions requires the database (at ~/.local/share/amarok/mysqle/) to be manually backed up beforehand.

Aligning with current major KDE Frameworks version should simplify various direct and indirect software dependencies. However, phonon-vlc is the only supported backend on Qt6 Phonon, which Amarok 3.3 beta is still using for audio playback. This imposes some constraints e.g. on equalizer and analyzer functionalities. A more comprehensive overview of audio backend status is available on an invent.kde.org issue and a related work-in-progress merge request.

Additionally, there isn't official releases with Qt6 support of liblastfm available yet (needed for last.fm support). To enable the functionality, one needs to use library version built from e.g. sources at https://github.com/Mazhoon/liblastfm/tree/81e8f9dc16a0a18fe9a066d51c2071086326670b .

The Amarok 3.3 beta source tarball is available on download.kde.org and it has been signed with Tuomas Nurmi's GPG key. In addition to the source code, it is likely that some distributions will provide beta packages. The various nightly git builds provided by various splendid packagers should also provide a way of using the beta changes and participating in the testing.

Happy listening!

Final update

So this is my final blog regarding the Season of KDE 2025, I’m feeling happy for what I accomplished. Over the past few weeks, I’ve implemented PvP system for mancala game, this project has been a deep dive into game development, networking and user experience.

Summary of work done so far

1. Move tracking Mechanics

At the heart of this project lies the MankalaEngine, an engine designed to handle rules and gameplay of various mancala variants. I’ve added some more feature in the engine:

  • Move tracking: The lastMoveMethod() method allows to retrieve the last move played by the player and computer.

2. PvP Mode

It allows the real-time multiplayer gameplay using XMPP. Following is a brief summary:

  • XMPP Integration: Players connect to each other using their jabber IDs and exchange move using the established chat room in real-time.
  • Turn Management: The Player 1 always start, and turns alternate between the two players.
  • Board Syncing: Players manually update their boards based on the opponent’s move, ensuring both the players have accurate view of the game state.

3. Man Page Documentation

To make the game accesible, I’ve created a man page for bohnenspieltui. This man page provides the information abou the game, including:

  • Synopsis and Description: A brief overview and explanation of the game variant.
  • Usage: Instructions for running the PvP mode.
  • Added a minor improvement of card view in Mancala GUI.

Future Work

While the task for this term is completed, their are several areas for improvement:

  • Automated board syncing by replacing the current manual one.
  • Integrating the engine to the mancala GUI.
  • Extending the PvP to other variants.

Final Words

Thanks to KDE community, XMPP community and Benson Muite and João Gouveia and Blue from Macaw.me for the guidance and support. And I encourage the aspiring contributors to take part in Season of KDE to learn and grow as a developer.

Saturday, 12 April 2025

Work done so far

Implemented the PvP mode by leveraging XMPP for communication, enabling the played to exchange moves. The code for this are implementd in connection.h, connection.cpp and bohnenspieltui.cpp.

Setting up the PvP mode

The player select the game mode they desires to play, for PvP the choice would be option P.

Connecting to XMPP server

To establish the chat room and enable the communication the player must provide their jabber id and password and the opponent’s JID (This should be done from both players side).

The program then establishes a connection to the XMPP server using the entered credentials. The game proceeds only when the credentials are verified.

Host and Turn Order

The program determines who will play first in a simple manner i.e., by comparing the lexicographical order of their jabber IDs.

Sending a move

When it’s player turn, they are prompted to enter their move. The move is validated and sent to opponent via the established chat room.

The board is updated locally and then the turn is passed to the opponent.

Receiving a move

When the move is received from the opponent, the program prompts the player to sync the board manually.

This is to ensure that both the players have their board in sync. Then the program prompts the user to enter their move and it game will be continued.

What’s next

  • Automatic move sync
  • The man page to explain the working to players.

Thursday, 10 April 2025

Wednesday, 9 April 2025

Some time ago we reached out to Wesley Gardner because, a bit belatedly, we saw he has published a great book on Krita, titled Draw and Paint Better with Krita.

For krita.org, Wesley wrote an introduction to his book!


Teaching art has been a passion of mine for a long time, and seeing students find their “inner voice” and push through barriers they thought insurmountable is one of the coolest things in the world. In 2021, I was approached to write a “how to digital paint” book, geared towards beginners to digital art, but with the goal of also having enough weight to give intermediate and advanced digital artists some fun exercises as well. Without second thought, I agreed, and knew that Krita would be the focal point of the book. Thus, in 2022, ‘Draw and Paint Better with Krita’ was published worldwide, and has become a sort of “guardian angel” guide for artists around the world, which I’m super humbled by and grateful for.

:

Krita’s everything that I believe digital art is about: Open access, customizable to fit your needs, easy to get started, and impossible to master. There’s always something new to learn in art, and likewise, there’s always something fun to learn in Krita. Whether it’s the various effects you can get with the ever-expanding layer management and adjustments, or the near-infinite pool of incredible custom brushes made by the community, there’s ALWAYS a new way to push yourself to that next level in your journey.

Cover

I’ve been a Krita user since Krita 3, and seeing how much it has evolved and expanded in the past few years has been unbelievable! It’s always installed on EVERY machine that I make art on, and is one of my “must-download” softwares the moment I get a new machine. It’s one of those programs that grows with you, and can handle absolutely anything you can throw at it. I’ve produced personal work and art prints, as well as professional client work for the likes of Star Wars, Warhammer 40k, and Riot Games, and the program never breaks a sweat. When I’m stumped on what type of video to make for my YouTube channel, I can always fall back on playing around in Krita, as it’s always a treat to poke around and learn new workflows.

Writing the book on Krita was a no-brainer, as I think learning Krita can help you learn ANY digital painting software, as the workflows are so similar. It’s the perfect entry-point for every artist that wants to work digitally, and it’s the perfect ending point for tenured veterans that need a little bit of “extra spice” to finish off their work and build their brand. If there’s one digital art program every single person needs on their machine, it’s Krita.

For real, what CAN’T Krita do? Go join the forums, be part of the community, and (if you’re financially able to, of course) donate somewhat regularly to the Krita Foundation. They do incredible work, and the fact that Krita’s available on Windows, Mac, AND Linux, for FREE, is still some sort of wizardry I can’t wrap my head around. For the Krita Team: Keep knocking it out of the park, it’s an honor to be a part of the Krita legacy, and for the team, and all artists out there:

Go make cool art.

Monday, 7 April 2025

Icy morning Witch Wells Az
Icy morning Witch Wells Az

Life:

Last week we were enjoying springtime, this week winter has made a comeback! Good news on the broken arm front, the infection is gone, so they can finally deal with the broken issue again. I will have a less invasive surgery April 25th to pull the bones back together so they can properly knit back together! If you can spare any change please consider a donation to my continued healing and recovery, or just support my work 🙂

Kubuntu:

While testing Beta I came across some crashy apps ( Namely PIM ) due to apparmor. I have uploaded fixed profiles for kmail, akregator, akonadiconsole, konqueror, tellico

KDE Snaps:

Added sctp support in Qt https://invent.kde.org/neon/snap-packaging/kde-qt6-core-sdk/-/commit/bbcb1dc39044b930ab718c8ffabfa20ccd2b0f75

This will allow me to finish a pyside6 snap and fix FreeCAD build.

Changed build type to Release in the kf6-core24-sdk which will reduce the size of kf6-core24 significantly.

Fixed a few startup errors in kf5-core24 and kf6-core24 snapcraft-desktop-integration.

Soumyadeep fixed wayland icons in https://invent.kde.org/neon/snap-packaging/kf6-core-sdk/-/merge_requests/3

KDE Applications 25.03.90 RC released to –candidate ( I know it says 24.12.3, version won’t be updated until 25.04.0 release )

Kasts core24 fixed in –candidate

Kate now core24 with Breeze theme! –candidate

Neochat: Fixed missing QML and 25.04 dependencies in –candidate

Kdenlive now with Galxnimate animations! –candidate

Digikam 8.6.0 now with scanner support in –stable

Kstars 3.7.6 released to –stable for realz, removed store rejected plugs.

Thanks for stopping by!

Saturday, 5 April 2025

Work done so far

Move tracker for PvC game

Implemented the code for tracking the move played by player and computer in bohnenspiel TUI game.

It is achieved using getLastMove method initialized and defined in mankalaengine.h and mankalaengine.cpp. This method returns a pair containing the last moved as int played and the player as Player who made it.

During each iteration of the game loop, the above method is called for both player and computer to retrieve their respective last moves.

The above code in TUI file of bohnenspiel game variant is used to display the move played in the terminal.

The player move is tracked using user.getLastMove() and the computer move is tracked using opponent.getLastMove(). The game loop alternates between the player and the computer, updating the board and tracking moves after each turn. The last moves are printed after each turn. The computer’s move are adjusted by adding 6 to align it’s side of board(move 6-11).

How it works?

  1. Player’s Turn:
    • The player select the hole to play.
    • The move is played, and the board is updated.
    • The move is tracked using user.getLastMove().
  2. Computer’s Turn:
    • The computer select the hole to play.
    • The move is played, and the board is updated.
    • The move is tracked using opponent.getLastMove().

After each turn the last moves played are displayed.

What’s next

The next goal moving forward is to create a PvP game mode for two different users.

Thursday, 3 April 2025

Model/View Drag and Drop in Qt - Part 3

In this third blog post of the Model/View Drag and Drop series (part 1 and part 2), the idea is to implement dropping onto items, rather than in between items. QListWidget and QTableWidget have out of the box support for replacing the value of existing items when doing that, but there aren't many use cases for that. What is much more common is to associate a custom semantic to such a drop. For instance, the examples detailed below show email folders and their contents, and dropping an email onto another folder will move (or copy) the email into that folder.

Blog_Drag&Drop_Qt_part3-treeview-step1

Step 1

Initial state, the email is in the inbox

Blog_Drag&Drop_Qt_part3-treeview-step2

Step 2

Dragging the email onto the Customers folder

Blog_Drag&Drop_Qt_part3-treeview-step3

Step 3

Dropping the email

Blog_Drag&Drop_Qt_part3-treeview-step4

Step 4

The email is now in the customers folder

With Model/View separation

Example code can be found here for flat models and here for tree models.

Setting up the view on the drag side

☑ Call view->setDragDropMode(QAbstractItemView::DragOnly)
unless of course the same view should also support drops. In our example, only emails can be dragged, and only folders allow drops, so the drag and drop sides are distinct.

☑ Call view->setDragDropOverwriteMode(...)
true if moving should clear cells, false if moving should remove rows.
Note that the default is true for QTableView and false for QListView and QTreeView. In our example, we want to remove emails that have been moved elsewhere, so false is correct.

☑ Call view->setDefaultDropAction(Qt::MoveAction) so that the drag defaults to a move and not a copy, adjust as needed

Setting up the model on the drag side

To implement dragging items out of a model, you need to implement the following -- this is very similar to the section of the same name in the previous blog post, obviously:

class EmailsModel : public QAbstractTableModel
{
    ~~~
    Qt::ItemFlags flags(const QModelIndex &index) const override
    {
        if (!index.isValid())
            return {};
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
    }

    // the default is "copy only", change it
    Qt::DropActions supportedDragActions() const override { return Qt::MoveAction | Qt::CopyAction; }

    QMimeData *mimeData(const QModelIndexList &indexes) const override;

    bool removeRows(int position, int rows, const QModelIndex &parent) override;

☑ Reimplement flags() to add Qt::ItemIsDragEnabled in the case of a valid index

☑ Reimplement supportedDragActions() to return Qt::MoveAction | Qt::CopyAction or whichever you want to support (the default is CopyAction only).

☑ Reimplement mimeData() to serialize the complete data for the dragged items. If the views are always in the same process, you can get away with serializing only node pointers (if you have that) and application PID (to refuse dropping onto another process). See the previous part of this blog series for more details.

☑ Reimplement removeRows(), it will be called after a successful drop with MoveAction. An example implementation looks like this:

bool EmailsModel::removeRows(int position, int rows, const QModelIndex &parent)
{
    beginRemoveRows(parent, position, position + rows - 1);
    for (int row = 0; row < rows; ++row) {
        m_emailFolder->emails.removeAt(position);
    }
    endRemoveRows();
    return true;
}

Setting up the view on the drop side

☑ Call view->setDragDropMode(QAbstractItemView::DropOnly) unless of course it supports dragging too. In our example, we can drop onto email folders but we cannot reorganize the folders, so DropOnly is correct.

Setting up the model on the drop side

To implement dropping items into a model's existing items, you need to do the following:

class FoldersModel : public QAbstractTableModel
{
    ~~~    
    Qt::ItemFlags flags(const QModelIndex &index) const override
    {
        CHECK_flags(index);
        if (!index.isValid())
            return {}; // do not allow dropping between items
        if (index.column() > 0)
            return Qt::ItemIsEnabled | Qt::ItemIsSelectable; // don't drop on other columns
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
    }

    // the default is "copy only", change it
    Qt::DropActions supportedDropActions() const override { return Qt::MoveAction | Qt::CopyAction; }
  
    QStringList mimeTypes() const override { return {QString::fromLatin1(s_emailsMimeType)}; }
  
    bool dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
};

☑ Reimplement flags()
For a valid index (and only in that case), add Qt::ItemIsDropEnabled. As you can see, you can also restrict drops to column 0, which can be more sensible when using QTreeView (the user should drop onto the folder name, not onto the folder size).

☑ Reimplement supportedDropActions() to return Qt::MoveAction | Qt::CopyAction or whichever you want to support (the default is CopyAction only).

☑ Reimplement mimeTypes() - the list should include the MIME type used by the drag model.

☑ Reimplement dropMimeData()
to deserialize the data and handle the drop.
This could mean calling setData() to replace item contents, or anything else that should happen on a drop: in the email example, this is where we copy or move the email into the destination folder. Once you're done, return true, so that the drag side then deletes the dragged rows by calling removeRows() on its model.

bool FoldersModel::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
    ~~~  // safety checks, see full example code

    EmailFolder *destFolder = folderForIndex(parent);

    const QByteArray encodedData = mimeData->data(s_emailsMimeType);
    QDataStream stream(encodedData);
    ~~~ // code to detect and reject dropping onto the folder currently holding those emails

    while (!stream.atEnd()) {
        QString email;
        stream >> email;
        destFolder->emails.append(email);
    }
    emit dataChanged(parent, parent); // update count

    return true; // let the view handle deletion on the source side by calling removeRows there
}

Using item widgets

Example code:

On the "drag" side

☑ Call widget->setDragDropMode(QAbstractItemView::DragOnly) or DragDrop if it should support both

☑ Call widget->setDefaultDropAction(Qt::MoveAction) so that the drag defaults to a move and not a copy, adjust as needed

☑ Reimplement Widget::mimeData() to serialize the complete data for the dragged items. If the views are always in the same process, you can get away with serializing only item pointers and application PID (to refuse dropping onto another process). In our email folders example we also serialize the pointer to the source folder (where the emails come from) so that we can detect dropping onto the same folder (which should do nothing).

To serialize pointers in QDataStream, cast them to quintptr, see the example code for details.

On the "drop" side

☑ Call widget->setDragDropMode(QAbstractItemView::DropOnly) or DragDrop if it should support both

☑ Call widget->setDragDropOverwriteMode(true) for a minor improvement: no forbidden cursor when moving the drag between folders. Instead Qt only computes drop positions which are onto items, as we want here.

☑ Reimplement Widget::mimeTypes() and return the same name as the one used on the drag side's mimeData

☑ Reimplement Widget::dropMimeData() (note that the signature is different between QListWidget, QTableWidget and QTreeWidget) This is where you deserialize the data and handle the drop. In the email example, this is where we copy or move the email into the destination folder.

Make sure to do all of the following:

  • any necessary behind the scenes work (in our case, moving the actual email)
  • updating the UI (creating or deleting items as needed)

This is a case where proper model/view separation is actually much simpler.

Improvements to Qt

While writing and testing these code examples, I improved the following things in Qt, in addition to those listed in the previous blog posts:

  • QTBUG-2553 QTreeView with setAutoExpandDelay() collapses items while dragging over it, fixed in Qt 6.8.1

Conclusion

I hope you enjoyed this blog post series and learned a few things.

The post Model/View Drag and Drop in Qt - Part 3 appeared first on KDAB.