QFileDialog combine MIME type filters to "All formats" - c++

I am using Qt 5.9 to open a file dialog asking the user to select an image file:
QStringList mimeTypeFilters;
const QByteArrayList supportedMimeTypes = QImageReader::supportedMimeTypes();
foreach(const QByteArray& mimeTypeName, supportedMimeTypes) {
mimeTypeFilters.append(mimeTypeName);
}
mimeTypeFilters.sort();
QFileDialog* fileDialog = new QFileDialog(this, "Select image");
fileDialog->setMimeTypeFilters(mimeTypeFilters);
fileDialog->setFileMode(QFileDialog::ExistingFile);
fileDialog->exec();
All supported image formats are added as MIME type filters to the dialog, which is working quite well. However, I want to add an additional filter (such as "All formats" or "All supported") that allows the user to select an image of ANY of the supported formats, as selecting the correct format prior to selecting the image is quite tedious. What is the most elegant solution to achieve this, without subclassing any of the involved Qt classes?

Thanks to SteakOverflow's comment, here is the solution I came up with:
// get supported image file types
QStringList mimeTypeFilters;
const QByteArrayList supportedMimeTypes = QImageReader::supportedMimeTypes();
foreach(const QByteArray& mimeTypeName, supportedMimeTypes) {
mimeTypeFilters.append(mimeTypeName);
}
mimeTypeFilters.sort(Qt::CaseInsensitive);
// compose filter for all supported types
QMimeDatabase mimeDB;
QStringList allSupportedFormats;
for(const QString& mimeTypeFilter: mimeTypeFilters) {
QMimeType mimeType = mimeDB.mimeTypeForName(mimeTypeFilter);
if(mimeType.isValid()) {
allSupportedFormats.append(mimeType.globPatterns());
}
}
QString allSupportedFormatsFilter = QString("All supported formats (%1)").arg(allSupportedFormats.join(' '));
QFileDialog* fileDialog = new QFileDialog(this, "Select image");
fileDialog->setFileMode(QFileDialog::ExistingFile);
fileDialog->setMimeTypeFilters(mimeTypeFilters);
QStringList nameFilters = fileDialog->nameFilters();
nameFilters.append(allSupportedFormatsFilter);
fileDialog->setNameFilters(nameFilters);
fileDialog->selectNameFilter(allSupportedFormatsFilter);
It is basically the same implementation QFileDialog uses internally to convert mime type filters to name filters. The new name filter for all supported formats will be added at the bottom of the filter list and pre-selected. The filter string is quite long and not fully visible in the dialog at once, but will become fully visible once the user opens the drop-down menu.

Related

Replacing Field values in Word Document QAxObject QT / C++

I'm really new to QT and I was tasked to update some field values in word document programmatically, currently I can replace text from word document fine, but when that field value is inside an object (table or anything) it's not working, my code is:
QString outFile("D:\\#test files\\output.docx");
QString inFile1("D:\\#test files\\input.docx");
QAxObject axObject("Word.Application");
QAxObject* documents = axObject.querySubObject("Documents");
QAxObject* document = documents->querySubObject("Open(const QString&, bool)", inFile1, true);
QAxObject* selection = axObject.querySubObject("Selection");
auto find = selection->querySubObject("Find");
QString sOld = "${name}";
QString sNew = "Ibrahim";
bool bMatchCase = false;
bool bMatchWholeWord = false;
bool bMatchWildCards = false;
bool bReplaceAll = true;
QVariantList vl = { sOld, bMatchCase, bMatchWholeWord, bMatchWildCards, false, false, true, 1, false, sNew, bReplaceAll ? "2" : "1" };
find->dynamicCall("Execute(QString,bool,bool,bool,bool,bool,bool,int,bool,QString,int)", vl);
document->dynamicCall("SaveAs(const QString&)", outFile);
document->dynamicCall("Close()");
axObject.dynamicCall("Quit()");
If you can help it would be awesome :)
If you can change the nature of the target files, you would do well replacing your targets with real Word DocVariable or DocProperty fields. Then use your code to change the variable or properties and update the related fields in the documents. Some document properties (under the Quick Parts > Document Properties menu) are mapped to XML data points and do not require updating of fields if those are used.
The placeholder can be (1) a DocVariable field or (2) a DocProperty field. You can change the variables or properties using code and then update the field.
You can also use one of the built-in mapped Document Property Content Controls in which case there is no need to update a field if the property is changed. It is automatic. More on these in my related page: Repeating Data Mapped Document Property Content Controls or Other Mapped Content Controls.
Here are links to two Word MVP pages on accessing Document Properties using vba.
How Can I Get Access to the Document Properties of a Document Without Opening the Document
How to Use a Single vba Procedure to Read or Write Both Built-In and Custom Document Properties

How to use a custom validation function for a QCompleter in a QComboBox

I have a string matching function to be used for searching for names that is more advanced than QString::contains() (e. g. when you search for "mueller", it will match "Müller").
I'd like to use this function to search inside a QComboBox. The default completion almost does what I need: If I do
combobox->setEditable(true);
combobox->setInsertPolicy(QComboBox::NoInsert);
combobox->completer()->setCompletionMode(QCompleter::PopupCompletion);
and type some text in the QComboBox's lineedit, the popup pops up, only showing entries starting what has been typed.
This is what I want, but I would like the QCompleter to evaluate matches using my search function rather than the QString::startsWith() that is apparently used here (and setting the mode to Qt::MatchContains is better but still not sufficient).
Is there any way to customize the completer's search function?
Thanks for all help!
I ended up using an own QCompleter and set it for the QComboBox's QLineEdit. The completer does not use the combobox's model, but an own one, which is filled with data everytime the entered text changes.
Can be done as follows:
m_matchingNames = new QStringListModel(this);
m_nameCompleter = new QCompleter(m_matchingNames, this);
m_nameCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
m_playersSelect->setEditable(true);
m_playersSelect->setInsertPolicy(QComboBox::NoInsert);
m_playersSelect->setCompleter(0);
m_playersSelect->lineEdit()->setCompleter(m_nameCompleter);
connect(m_playersSelect->lineEdit(), &QLineEdit::textEdited, this, &ScorePage::nameSearchChanged);
and
void ScorePage::nameSearchChanged(const QString &text)
{
QStringList possibleNames;
for (const QString &name : m_availableNames) {
if (checkMatch(name, text)) {
possibleNames << name;
}
}
m_matchingNames->setStringList(possibleNames);
}
Most probably not the most prerformant solution, but it works :-)
One then can also connect to QCompleter::activated() to process what has been chosen from the list and e. g. do a QComboBox::setCurrentIndex() or such.

How can I display the image as a thumbnail

I have a QTreeView to display the hard drives and Directories. also I have a QListView to display the images files as the following:
But I want to display the images as thumbnails, like the following:
My code:
mainWidget::mainWidget(QWidget *parent) : QWidget(parent), ui(new Ui::mainWidget){
ui->setupUi(this);
dirsModel = new QFileSystemModel;
filesModel = new QFileSystemModel;
dirsModel->setRootPath("");
ui->treeView->setModel(dirsModel);
ui->listView->setModel(filesModel);
dirsModel->setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
filesModel->setFilter(QDir::Files);
ui->treeView->hideColumn(1);
ui->treeView->hideColumn(2);
ui->treeView->hideColumn(3);
ui->treeView->header()->hide();
}
void mainWidget::on_treeView_clicked(const QModelIndex &index){
ui->listView->setRootIndex(filesModel->setRootPath(dirsModel->filePath(index)));
}
Unfortunately, I don't know what is the way of changing the image view from icon to thumbnail.
Depending on what you are after there are better ways to go about it I think, but here is an example based on a project of mine in python:
What you can do is subclass the QFileIconProvider:
ICON_SIZE = QSize(64,64)
accepted_types = (".jpg",".tiff",".png",".exr",".psd")
# this depends on the plugins you have installed,
# PSD and EXR requires external ones).
class IconProvider(QFileIconProvider):
def __init__(self) -> None:
super().__init__()
def icon(self, type: 'QFileIconProvider.IconType'):
fn = type.filePath()
if fn.endswith(accepted_types):
a = QPixmap(ICON_SIZE)
a.load(fn)
return QIcon(a)
else:
return super().icon(type)
Then on the Model you use:
self.fileSystemModel.setIconProvider(IconProvider)
Example on TreeView:
You should use special ViewMode:
ui->listView->setViewMode(QListView::IconMode);
But it will show you only icons(not whole images), so I think you should create for example QStandardItemModel (because QFileSystemModel is not very suitable) and set pixmap to this model with Qt::DecorationRole, but scale this images to smaller size. As you understand if there are many images in the dir, this process can be long.
As you can see, you should every time (every on_treeView_clicked) get new list of images in the directory, You can do this with:
QStringList QDir::entryList(const QStringList & nameFilters, Filters filters = NoFilter, SortFlags sort = NoSort) const
with special filters. When you have list of files, in the loop you can create pixmaps, scale it and set to model.
By default QListView::IconMode provide Free movement. If you want avoid this you should use:
ui->listView->setMovement(QListView::Static);

Qt: Linking my model data with a QListView

I'm writing my first Qt project (so I'm new to the environment) and I've got this project build using the MVC design pattern.
It's a pretty basic note manager/editor. I've got a class uiman ("Ui Manager") which takes care of my UI, and my function to open a notes database (which is just a list of text files to open)
void uiman::openDBDialog(){
QFileDialog dialog;
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setDirectory("/Users/myuserdir/Desktop");
dialog.setFilter(QDir::Files);
dialog.setWindowTitle("Open File");
dialog.setNameFilter("Textie Notes DB(*.db)");
dialog.exec();
QString pathDB = dialog.selectedFiles().first();
model = new notesModel();
model->setNotesDB(new QString(pathDB.toUtf8().constData()));
refreshAll();
}
so far, so good. I take the path of my database and give it to my model, which should now manage the rest.
Now, the refreshAll() function should take the list I opened up and show them in my QListView, but I can't parse the file and append items on the go using clear() and append() unlike the QListWidget. So, how do I approach building a vector (I suppose) of names from my file and feeding them to my QListView?
Sorry if I'm not being clear, but the official documentation hasn't been clear enough.
Edit: This is my model, nodesmodel, and here's the code.
notesModel::notesModel(QObject *parent) :
QFileSystemModel(parent)
{
QStringList noteList;
}
void notesModel::setNotesDB(QString *dbpath){
// open the notes database
databasepath = dbpath;
}
QFile* notesModel::getDB(){
if(this->dbFile == NULL)
this->dbFile = new QFile(databasepath- >toUtf8().constData());
return this->dbFile;
}
As you already noticed, you do not add/remove data from the viewer widget itself, this is done in the model.
You can set the model with the setModel() method.
If you want to show a simple QString list, then you can use:
QStringList strings;
strings << "String 1" << "String 2" << "String 3";
model = new QStringListModel(strings, parent);
view->setModel(model);
// model is managed by parent, and will be deleted when parent is deleted.
// If you create multiple models you might consider other memory management strategy
To read a text file and store its lines in a QStringList, see this answer.

QT tree that allows multiselection

I'm making a simple file explorer and I ran into some problems with Qt. I want to show the user a tree view of files on his computer, but I also want to be able to select multiple files/directories and do something with them later on (by selecting checkboxes or multiple select using ctrl+left click or shift+left click). I've placed the QTreeView element and set up a model to it (QFileSystemModel). It gives me a good tree view, but I can't modify the headers (column names) or add my own column with checkbox in every row (for example). Qt is new to me, I've searched for few good hours for some tips/solutions, but nothing is working with QFileSystemModel. Is there anything I can do to get this working?
The code is short and simple:
QString lPath = "C:/";
QString rPath = "C:/";
leftTree_model = new QFileSystemModel(this);
rightTree_model = new QFileSystemModel(this);
leftTree_model->setRootPath(lPath);
rightTree_model->setRootPath(rPath);
//i have actually 2 tree views that work the same
ui->leftTree->setModel(leftTree_model); //ui->leftTree is the first tree view
ui->rightTree->setModel(rightTree_model); //the second
Use something of the following:
CheckStateRole to add checkboxes to your model. To do this, you inherit your custom item model (which you're going to use) from the QFileSystemModel, and reimplement the data() method, where you return bool values for CheckStateRole. You will also need the QAbstractItemModel::setData method to handle changes. You can also check the docs for QAbstractItemModel to see how to change header texts (headerData())
Change the selection mode of your view to allow multiple selections
EDIT:
here's a sample code to inherit from the model
class MyFancyModel : public QFileSystemModel
{
public:
MyFancyModel(QObject* pParent = NULL) : QFileSystemModel(pParent)
{
}
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole ) const
{
if (role == Qt::CheckStateRole)
{
// stub value is true
return true; // here you will return real values
// depending on which item is currently checked
}
return QFileSystemModel::data(index, role);
}
};