Work on editability of models.

master
Jos van den Oever 2017-08-19 00:53:13 +02:00
parent b94d65a217
commit a5f22ad04b
7 changed files with 174 additions and 11 deletions

View File

@ -14,6 +14,7 @@ use std::collections::HashMap;
pub struct DirEntry {
name: OsString,
metadata: Option<Metadata>,
path: Option<PathBuf>
}
type Incoming<T> = Arc<Mutex<HashMap<usize, Vec<T>>>>;
@ -23,6 +24,7 @@ impl Item for DirEntry {
DirEntry {
name: OsString::from(name),
metadata: metadata(name).ok(),
path: None
}
}
fn can_fetch_more(&self) -> bool {
@ -31,6 +33,17 @@ impl Item for DirEntry {
fn file_name(&self) -> String {
self.name.to_string_lossy().to_string()
}
fn file_path(&self) -> Option<String> {
self.path.as_ref().map(|p| p.to_string_lossy().into())
}
fn set_file_name(&mut self, file_name: String) -> bool {
self.name = file_name.into();
true
}
fn set_file_path(&mut self, file_path: Option<String>) -> bool {
self.path = file_path.map(|f| f.into());
true
}
fn file_permissions(&self) -> c_int {
42
}
@ -46,11 +59,12 @@ impl Item for DirEntry {
let mut v = Vec::new();
let path: PathBuf = parents.into_iter().map(|e| &e.name).collect();
thread::spawn(move || {
if let Ok(it) = read_dir(path) {
if let Ok(it) = read_dir(&path) {
for i in it.filter_map(|v| v.ok()) {
let de = DirEntry {
name: i.file_name(),
metadata: i.metadata().ok()
metadata: i.metadata().ok(),
path: Some(i.path())
};
v.push(de);
}
@ -70,6 +84,7 @@ impl Default for DirEntry {
DirEntry {
name: OsString::new(),
metadata: None,
path: None
}
}
}
@ -79,9 +94,12 @@ pub trait Item: Default {
fn can_fetch_more(&self) -> bool;
fn retrieve(id: usize, parents: Vec<&Self>, q: Incoming<Self>, emit: TreeEmitter);
fn file_name(&self) -> String;
fn file_path(&self) -> Option<String>;
fn set_file_name(&mut self, file_name: String) -> bool;
fn file_permissions(&self) -> c_int;
fn file_type(&self) -> c_int;
fn file_size(&self) -> Option<u64>;
fn set_file_path(&mut self, file_path: Option<String>) -> bool;
}
pub type Tree = RGeneralItemModel<DirEntry>;
@ -145,6 +163,10 @@ impl<T: Item> RGeneralItemModel<T> where T: Sync + Send {
self.get_index(row, parent)
.map(|i| &self.entries[i])
}
fn get_mut(&mut self, row: c_int, parent: usize) -> Option<&mut Entry<T>> {
self.get_index(row, parent)
.map(move |i| &mut self.entries[i])
}
fn retrieve(&mut self, row: c_int, parent: usize) {
let id = self.get_index(row, parent).unwrap();
let parents = self.get_parents(id);
@ -258,6 +280,11 @@ impl<T: Item> TreeTrait for RGeneralItemModel<T> where T: Sync + Send {
.map(|entry| entry.data.file_name())
.unwrap_or_default()
}
fn set_file_name(&mut self, row: c_int, parent: usize, v: String) -> bool {
self.get_mut(row, parent)
.map(|mut entry| entry.data.set_file_name(v))
.unwrap_or(false)
}
fn file_permissions(&self, row: c_int, parent: usize) -> c_int {
self.get(row, parent)
.map(|entry| entry.data.file_permissions())
@ -267,7 +294,9 @@ impl<T: Item> TreeTrait for RGeneralItemModel<T> where T: Sync + Send {
Vec::new()
}
fn file_path(&self, row: c_int, parent: usize) -> Option<String> {
None
self.get(row, parent)
.map(|entry| entry.data.file_path())
.unwrap_or_default()
}
fn file_type(&self, row: c_int, parent: usize) -> c_int {
self.get(row, parent)
@ -279,4 +308,9 @@ impl<T: Item> TreeTrait for RGeneralItemModel<T> where T: Sync + Send {
.map(|entry| entry.data.file_size())
.unwrap_or(None)
}
fn set_file_path(&mut self, row: c_int, parent: usize, v: Option<String>) -> bool {
self.get_mut(row, parent)
.map(|mut entry| entry.data.set_file_path(v))
.unwrap_or(false)
}
}

View File

@ -79,8 +79,10 @@ pub trait TreeTrait {
fn fetch_more(&mut self, c_int, usize) {}
fn sort(&mut self, c_int, SortOrder) {}
fn file_name(&self, row: c_int, parent: usize) -> String;
fn set_file_name(&mut self, row: c_int, parent: usize, String) -> bool;
fn file_icon(&self, row: c_int, parent: usize) -> Vec<u8>;
fn file_path(&self, row: c_int, parent: usize) -> Option<String>;
fn set_file_path(&mut self, row: c_int, parent: usize, Option<String>) -> bool;
fn file_permissions(&self, row: c_int, parent: usize) -> i32;
fn file_type(&self, row: c_int, parent: usize) -> i32;
fn file_size(&self, row: c_int, parent: usize) -> Option<u64>;
@ -191,6 +193,11 @@ pub unsafe extern "C" fn tree_data_file_path(ptr: *const Tree,
}
}
#[no_mangle]
pub unsafe extern "C" fn tree_set_data_file_path_none(ptr: *mut Tree, row: c_int, parent: usize) -> bool {
(&mut *ptr).set_file_path(row, parent, None)
}
#[no_mangle]
pub unsafe extern "C" fn tree_data_file_permissions(ptr: *const Tree, row: c_int, parent: usize) -> i32 {
(&*ptr).file_permissions(row, parent).into()

View File

@ -179,7 +179,8 @@ void FibonacciList::sort(int column, Qt::SortOrder order)
}
Qt::ItemFlags FibonacciList::flags(const QModelIndex &i) const
{
return QAbstractItemModel::flags(i);
auto flags = QAbstractItemModel::flags(i);
return flags;
}
QVariant FibonacciList::data(const QModelIndex &index, int role) const
{

View File

@ -121,6 +121,7 @@ extern "C" {
void tree_data_file_name(const Tree::Private*, int, quintptr, QString*, qstring_set);
void tree_data_file_icon(const Tree::Private*, int, quintptr, QByteArray*, qbytearray_set);
void tree_data_file_path(const Tree::Private*, int, quintptr, QString*, qstring_set);
bool tree_set_data_file_path_none(Tree::Private*, int, quintptr);
qint32 tree_data_file_permissions(const Tree::Private*, int, quintptr);
qint32 tree_data_file_type(const Tree::Private*, int, quintptr);
option<quint64> tree_data_file_size(const Tree::Private*, int, quintptr);
@ -190,7 +191,14 @@ void Tree::sort(int column, Qt::SortOrder order)
}
Qt::ItemFlags Tree::flags(const QModelIndex &i) const
{
return QAbstractItemModel::flags(i);
auto flags = QAbstractItemModel::flags(i);
if (i.column() == 0) {
flags |= Qt::ItemIsEditable;
}
if (i.column() == 1) {
flags |= Qt::ItemIsEditable;
}
return flags;
}
QVariant Tree::data(const QModelIndex &index, int role) const
{
@ -204,6 +212,10 @@ QVariant Tree::data(const QModelIndex &index, int role) const
tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring);
if (!s.isNull()) v.setValue<QString>(s);
break;
case Qt::EditRole:
tree_data_file_name(d, index.row(), index.internalId(), &s, set_qstring);
if (!s.isNull()) v.setValue<QString>(s);
break;
case Qt::DecorationRole:
tree_data_file_icon(d, index.row(), index.internalId(), &b, set_qbytearray);
if (!b.isNull()) v.setValue<QByteArray>(b);
@ -233,6 +245,10 @@ QVariant Tree::data(const QModelIndex &index, int role) const
tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring);
if (!s.isNull()) v.setValue<QString>(s);
break;
case Qt::EditRole:
tree_data_file_path(d, index.row(), index.internalId(), &s, set_qstring);
if (!s.isNull()) v.setValue<QString>(s);
break;
}
break;
case 2:
@ -271,5 +287,33 @@ QHash<int, QByteArray> Tree::roleNames() const {
}
bool Tree::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.column() == 0) {
if (role == (Qt::DisplayRole)) {
return true;
}
if (role == (Qt::EditRole)) {
return true;
}
if (role == (Qt::UserRole + 1)) {
if (!value.isValid() || value.isNull()) {
return tree_set_data_file_path_none(d, index.row(), index.internalId());
}
return true;
}
}
if (index.column() == 1) {
if (role == (Qt::DisplayRole)) {
if (!value.isValid() || value.isNull()) {
return tree_set_data_file_path_none(d, index.row(), index.internalId());
}
return true;
}
if (role == (Qt::EditRole)) {
if (!value.isValid() || value.isNull()) {
return tree_set_data_file_path_none(d, index.row(), index.internalId());
}
return true;
}
}
return false;
}

View File

@ -67,7 +67,7 @@ int main (int argc, char *argv[])
auto root = sortedModel.index(0, 0);
view.expand(root);
view.sortByColumn(0, Qt::AscendingOrder);
// view.show();
view.show();
view.header()->setSectionResizeMode(QHeaderView::ResizeToContents);
QQmlApplicationEngine engine;

View File

@ -19,7 +19,13 @@
[{
"name": "fileName",
"value": "Qt::DisplayRole",
"type": "QString"
"type": "QString",
"write": true
}, {
"name": "fileName",
"value": "Qt::EditRole",
"type": "QString",
"write": true
}, {
"name": "fileIcon",
"value": "Qt::DecorationRole",
@ -28,6 +34,7 @@
"name": "filePath",
"value": "Qt::UserRole + 1",
"type": "QString",
"write": true,
"optional": true
}, {
"name": "fileName",
@ -51,6 +58,13 @@
"name": "filePath",
"value": "Qt::DisplayRole",
"type": "QString",
"write": true,
"optional": true
}, {
"name": "filePath",
"value": "Qt::EditRole",
"type": "QString",
"write": true,
"optional": true
}],
[{

View File

@ -335,6 +335,14 @@ signals:
)");
}
bool isWrite(const QList<Role>& roles) {
bool write = false;
for (auto role: roles) {
write = write | role.write;
}
return write;
}
void writeCppModel(QTextStream& cpp, const Object& o) {
const QString lcname(snakeCase(o.name));
QString indexDecl = ", int";
@ -353,6 +361,14 @@ void writeCppModel(QTextStream& cpp, const Object& o) {
cpp << QString(" %4 %2_data_%3(const %1::Private*%5);\n")
.arg(o.name, lcname, snakeCase(role.name), cppSetType(role), indexDecl);
}
if (role.write) {
// cpp << QString(" void %2_data_%3_set(%1::Private*, %3);")
// .arg(o.name, base, p.type.cSetType) << endl;
if (role.optional) {
cpp << QString(" bool %2_set_data_%3_none(%1::Private*%4);")
.arg(o.name, lcname, snakeCase(role.name), indexDecl) << endl;
}
}
}
cpp << QString(" void %2_sort(%1::Private*, int column, Qt::SortOrder order = Qt::AscendingOrder);\n").arg(o.name, lcname);
if (o.type == ObjectType::List) {
@ -470,7 +486,15 @@ void %1::sort(int column, Qt::SortOrder order)
}
Qt::ItemFlags %1::flags(const QModelIndex &i) const
{
return QAbstractItemModel::flags(i);
auto flags = QAbstractItemModel::flags(i);
)").arg(o.name, lcname);
for (int col = 0; col < o.columnRoles.size(); ++col) {
if (isWrite(o.columnRoles[col])) {
cpp << " if (i.column() == " << col << ") {\n";
cpp << " flags |= Qt::ItemIsEditable;\n }\n";
}
}
cpp << QString(R"( return flags;
}
QVariant %1::data(const QModelIndex &index, int role) const
{
@ -478,7 +502,7 @@ QVariant %1::data(const QModelIndex &index, int role) const
QString s;
QByteArray b;
switch (index.column()) {
)").arg(o.name, lcname);
)").arg(o.name);
for (int col = 0; col < o.columnRoles.size(); ++col) {
auto roles = o.columnRoles[col];
@ -513,9 +537,36 @@ QVariant %1::data(const QModelIndex &index, int role) const
cpp << QString(R"(}
bool %1::setData(const QModelIndex &index, const QVariant &value, int role)
{
return false;
}
)").arg(o.name);
for (int col = 0; col < o.columnRoles.size(); ++col) {
if (!isWrite(o.columnRoles[col])) {
continue;
}
cpp << " if (index.column() == " << col << ") {\n";
auto roles = o.columnRoles[col];
for (auto role: roles) {
if (!role.write) {
continue;
}
cpp << " if (role == (" << role.value << ")) {\n";
if (role.optional) {
QString test = "!value.isValid()";
if (role.type.isComplex()) {
test += " || value.isNull()";
}
cpp << " if (" << test << ") {\n";
cpp << QString(" return %1_set_data_%2_none(d%3);")
.arg(lcname, snakeCase(role.name), index) << endl;
cpp << " }\n";
}
cpp << " return true;\n";
cpp << " }\n";
}
cpp << " }\n";
}
cpp << R"( return false;
}
)";
}
void writeHeaderObject(QTextStream& h, const Object& o) {
@ -977,6 +1028,10 @@ pub trait %1Trait {
for (auto role: o.allRoles) {
r << QString(" fn %1(&self%3) -> %2;\n")
.arg(snakeCase(role.name), rustType(role), index);
if (role.write) {
r << QString(" fn set_%1(&mut self%3, %2) -> bool;\n")
.arg(snakeCase(role.name), rustType(role), index);
}
}
}
if (o.type == ObjectType::UniformTree) {
@ -1178,6 +1233,14 @@ pub unsafe extern "C" fn %2_data_%3(ptr: *const %1, row: c_int%5) -> %4 {
}
)").arg(o.name, lcname, snakeCase(role.name), rustCType(role), indexDecl, index);
}
if (role.write && role.optional) {
r << QString(R"(
#[no_mangle]
pub unsafe extern "C" fn %2_set_data_%3_none(ptr: *mut %1, row: c_int%4) -> bool {
(&mut *ptr).set_%3(row%5, None)
}
)").arg(o.name, lcname, snakeCase(role.name), indexDecl, index);
}
}
}
if (o.type == ObjectType::UniformTree) {