/* * PDFedit - free program for PDF document manipulation. * Copyright (C) 2006, 2007 PDFedit team: Michal Hocko, * Miroslav Jahoda, * Jozef Misutka, * Martin Petricek * * Project is hosted on http://sourceforge.net/projects/pdfedit */ /** @file "Merge documents pages" dialog
This dialog is used to select another PDF document and merge pages from that document in currently edited document */ #include "mergeform.h" #include "util.h" #include #include #include #include #include #include QLISTBOX #include #include namespace gui { using namespace pdfobjects; /** Data for ListItem. * Gathers ListItem type and page position information. */ struct NodeData { enum Type{ORIGINAL, FROMFILE}; /** Type of the item. */ Type type; /** Page position in type document. */ int position; /** Default constructor. * Initializes type to ORIGINAL and position to 0. */ NodeData():type(ORIGINAL), position(0) { } /** Initialization constructor. * @param _type Type value. * @param _position Position value. * * Doesn't perform any parameters checking. */ NodeData(Type _type, int _position):type(_type), position(_position) { } }; /** List box item. * Inherits from QListBoxText item type and adds NodeData data field. */ class ListItem:public Q_ListBoxText { NodeData * nodeData; public: ListItem(NodeData * _nodeData, Q_ListBox * _parent, const QString & text = QString::null):Q_ListBoxText(_parent, text), nodeData(_nodeData) { } ListItem(NodeData * _nodeData, const QString & text = QString::null):Q_ListBoxText(text), nodeData(_nodeData) { } ListItem(NodeData * _nodeData, Q_ListBox * _parent, const QString & text, Q_ListBoxItem * after):Q_ListBoxText(_parent, text, after), nodeData(_nodeData) { } /** Returns pointer to nodeData field. * @return Constant pointer to nodeData. */ const NodeData * getNodeData()const { return nodeData; } /** Returns pointer to nodeData field. * @return Pointer to nodeData. */ NodeData * getNodeData() { return nodeData; } /** Checks wheter this item has node data with given type. * @param type Type to compare with. * @return true if nodeData is non null and has the same type as given * one, false otherwise. */ bool isType(NodeData::Type type) { return (nodeData) && (nodeData->type == type); } }; void MergeDialog::mergeList_currentChanged( Q_ListBoxItem * item) { ListItem * listItem=dynamic_cast(item); if(listItem==NULL) return; // enables to manipulate only with FROMFILE nodes // original items has to be in same order as in // creation time if(listItem->isType(NodeData::FROMFILE)) { removeBtn->setEnabled(TRUE); // up button is enabled only if we are not in first // item if(mergeList->currentItem()>0) upBtn->setEnabled(TRUE); else upBtn->setEnabled(FALSE); // down button is enabled only if we are not on last // item if(mergeList->currentItem() + 1>=(int)(mergeList->count())) downBtn->setEnabled(FALSE); else downBtn->setEnabled(TRUE); } else { upBtn->setEnabled(FALSE); downBtn->setEnabled(FALSE); removeBtn->setEnabled(FALSE); } } void MergeDialog::fileList_currentChanged( Q_ListBoxItem * ) { // allways enable add button when something is selected if(!addBtn->isEnabled()) addBtn->setEnabled(TRUE); } void MergeDialog::addBtn_clicked() { int oldPos=-1; ListItem * oldItem=NULL; for(int i=fileList->count()-1; i>=0; --i) { // skips unselected items if(!fileList->isSelected(i)) continue; ListItem * fileItem=dynamic_cast(fileList->item(i)); if(!fileItem) continue; // removes fileItem from fileList oldPos=fileList->index(fileItem); oldItem=fileItem; fileList->takeItem(fileItem); if(oldPos>=(int)(fileList->count())) // correction for last item in list --oldPos; // gets position of selected item in mergeList int pos=mergeList->currentItem(); // insert fileItem before currently selected node in mergeList mergeList->insertItem(fileItem, (pos<0)?0:pos); mergeList->setSelected(fileItem, FALSE); } // sets new currentItem in mergeList to oldItem if(oldItem) { mergeList->setCurrentItem(oldItem); mergeList->setSelected(oldItem, TRUE); } // nothing has left in fileList box if(!fileList->count()) { addBtn->setEnabled(FALSE); return; } // select and mark as current element behind last added // to mergeList if(oldPos>=0) { fileList->setCurrentItem(oldPos); fileList->setSelected(oldPos, TRUE); return; } } void MergeDialog::removeBtn_clicked() { if(mergeList->selectedItem()) { ListItem * mergeItem=dynamic_cast(mergeList->selectedItem()); if(!mergeItem) { // nothing selected removeBtn->setEnabled(FALSE); return; } // removes item from mergeList int oldPos=mergeList->index(mergeItem); mergeList->takeItem(mergeItem); // insert to correct position in fileList - keeps ordering int pos=0; while(Q_ListBoxItem * item=fileList->item(pos)) { ListItem * i=dynamic_cast(item); if(!i) // bad type, this should not happen continue; // finish with first node with higer position // mergeItem will be stored before this position if(i->getNodeData()->position > mergeItem->getNodeData()->position) break; ++pos; } // inserts mergeItem to correct position and unselect it fileList->insertItem(mergeItem, pos); fileList->setCurrentItem(mergeItem); mergeList->setCurrentItem(oldPos); mergeList->setSelected(oldPos, TRUE); }else removeBtn->setEnabled(FALSE); } void MergeDialog::upBtn_clicked() { int pos=mergeList->currentItem(); if (pos>0) { // current item can be moved upwards Q_ListBoxItem * item=mergeList->item(pos); // removes and insert with decremented position mergeList->takeItem(item); mergeList->insertItem(item, pos-1); mergeList->setCurrentItem(item); } else upBtn->setEnabled(FALSE); } void MergeDialog::downBtn_clicked() { int pos=mergeList->currentItem(); if (pos<(int)(mergeList->count())) { Q_ListBoxItem * item=mergeList->item(pos); mergeList->takeItem(item); mergeList->insertItem(item, pos+1); mergeList->setCurrentItem(item); } else downBtn->setEnabled(FALSE); } void MergeDialog::openBtn_clicked() { // Fills fileList with items from opened file if(fileNameInput->text().isEmpty()) { // TODO dialog that nothing is specified return; } QString fileName=fileNameInput->text(); initFileList(fileName); // TODO handle when file doesn't exist or error occured // during CPdf creation // Open dialog causes disabling fileNameInput and fileNameBtn // and enabling merging stuff openBtn->setEnabled(FALSE); fileNameInput->setEnabled(FALSE); fileNameBtn->setEnabled(FALSE); mergeList->setEnabled(TRUE); fileList->setEnabled(TRUE); okBtn->setEnabled(TRUE); } void MergeDialog::fileNameBtn_clicked() { QString fileName = QFileDialog::getOpenFileName( QString::null, QObject::tr("PDF files (*.pdf)"), this, "file open", tr("Open file with pages to be inserted")); if(!fileName.isEmpty()) { fileNameInput->setText(fileName); } } MergeArray * MergeDialog::getResult() { int * pages=new int[mergeList->count()]; size_t * positions=new size_t[mergeList->count()]; size_t length=0; size_t storePos=1; for(size_t pos=0; pos < mergeList->count(); ++pos) { ListItem * item=dynamic_cast(mergeList->item(pos)); if(!item) continue; if(item->isType(NodeData::ORIGINAL)) { ++storePos; continue; } pages[length]=item->getNodeData()->position; positions[length]=storePos; ++length; } MergeArray * mergeArray=new MergeArray(length); mergeArray->initItems(pages); mergeArray->initPositions(positions); return mergeArray; } QString MergeDialog::fileName() { return fileNameInput->text(); } void MergeDialog::initOriginal( size_t count ) { char itemLabel[128]; for(size_t i=1; i<=count; ++i) { snprintf(itemLabel, 127, "Page%d", (int)i); //ListItem * listItem= new ListItem(new NodeData(NodeData::ORIGINAL, i), mergeList, itemLabel); } } void MergeDialog::destroyOpenFile() { // TODO - close CPdf instance if created } /** Initialize file list from given file name @param fileName name of PDF file @return true in case of success, false in case of failure (missing ,broken or unreadable pdf file) */ bool MergeDialog::initFileList( QString & fileName ) { CPdf *document; CPdf::OpenMode mode=CPdf::ReadOnly; try { guiPrintDbg(debug::DBG_DBG,"Opening document"); document=CPdf::getInstance(util::convertFromUnicode(fileName,util::NAME).c_str(),mode); assert(document); guiPrintDbg(debug::DBG_DBG,"Opened document"); } catch (PdfOpenException &ex) { std::string err; ex.getMessage(err); //TODO: some messagebox? return false; } size_t count = document->getPageCount(); document->close(); char itemLabel[128]; QFileInfo fi(fileName); QString baseName=fi.baseName(false); for(size_t i=1; i<=count; ++i) { snprintf(itemLabel, 127, "%s Page%d", baseName.ascii(), (int)i); //ListItem * listItem= new ListItem(new NodeData(NodeData::FROMFILE, i), fileList, itemLabel); } return true; } /* * Constructs a MergeDialog as a child of 'parent', with the * name 'name' and widget flags set to 'f'. * * The dialog will by default be modeless, unless you set 'modal' to * TRUE to construct a modal dialog. */ MergeDialog::MergeDialog( QWidget* parent, const char* name, bool modal, WFlags fl ) : QDialog( parent, name, modal, fl ) { if ( !name ) setName( "MergeDialog" ); MergeDialogLayout = new QGridLayout( this, 1, 1, 11, 6, "MergeDialogLayout"); layout48 = new QVBoxLayout( 0, 0, 6, "layout48"); layout27 = new QHBoxLayout( 0, 0, 6, "layout27"); textLabel1 = new QLabel( this, "textLabel1" ); textLabel1->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0, (QSizePolicy::SizeType)0, 0, 0, textLabel1->sizePolicy().hasHeightForWidth() ) ); layout27->addWidget( textLabel1 ); fileNameInput = new QLineEdit( this, "fileNameInput" ); fileNameInput->setEnabled( TRUE ); layout27->addWidget( fileNameInput ); fileNameBtn = new QPushButton( this, "fileNameBtn" ); fileNameBtn->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0, (QSizePolicy::SizeType)0, 0, 0, fileNameBtn->sizePolicy().hasHeightForWidth() ) ); fileNameBtn->setMaximumSize( QSize( 40, 32767 ) ); layout27->addWidget( fileNameBtn ); layout48->addLayout( layout27 ); layout2 = new QHBoxLayout( 0, 0, 6, "layout2"); spacer1 = new QSpacerItem( 131, 21, QSizePolicy::Expanding, QSizePolicy::Minimum ); layout2->addItem( spacer1 ); openBtn = new QPushButton( this, "openBtn" ); openBtn->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0, (QSizePolicy::SizeType)0, 0, 0, openBtn->sizePolicy().hasHeightForWidth() ) ); layout2->addWidget( openBtn ); spacer2 = new QSpacerItem( 151, 21, QSizePolicy::Expanding, QSizePolicy::Minimum ); layout2->addItem( spacer2 ); layout48->addLayout( layout2 ); line1 = new QFrame( this, "line1" ); line1->setFrameShape( QFrame::HLine ); line1->setFrameShadow( QFrame::Sunken ); line1->setFrameShape( QFrame::HLine ); layout48->addWidget( line1 ); layout47 = new QHBoxLayout( 0, 0, 6, "layout47"); mergeList = new Q_ListBox( this, "mergeList" ); mergeList->setEnabled( FALSE ); layout47->addWidget( mergeList ); layout4 = new QVBoxLayout( 0, 0, 6, "layout4"); addBtn = new QPushButton( this, "addBtn" ); addBtn->setEnabled( FALSE ); layout4->addWidget( addBtn ); removeBtn = new QPushButton( this, "removeBtn" ); removeBtn->setEnabled( FALSE ); layout4->addWidget( removeBtn ); spacer3 = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding ); layout4->addItem( spacer3 ); upBtn = new QPushButton( this, "upBtn" ); upBtn->setEnabled( FALSE ); layout4->addWidget( upBtn ); downBtn = new QPushButton( this, "downBtn" ); downBtn->setEnabled( FALSE ); layout4->addWidget( downBtn ); layout47->addLayout( layout4 ); fileList = new Q_ListBox( this, "fileList" ); fileList->setEnabled( FALSE ); fileList->setFrameShape( Q_ListBox::StyledPanel ); fileList->setSelectionMode( Q_ListBox::Extended ); layout47->addWidget( fileList ); layout48->addLayout( layout47 ); layout6 = new QHBoxLayout( 0, 0, 5, "layout6"); spacer5 = new QSpacerItem( 61, 21, QSizePolicy::Expanding, QSizePolicy::Minimum ); layout6->addItem( spacer5 ); okBtn = new QPushButton( this, "okBtn" ); okBtn->setEnabled( FALSE ); layout6->addWidget( okBtn ); spacer6 = new QSpacerItem( 41, 21, QSizePolicy::Expanding, QSizePolicy::Minimum ); layout6->addItem( spacer6 ); cancelBtn = new QPushButton( this, "cancelBtn" ); layout6->addWidget( cancelBtn ); layout48->addLayout( layout6 ); MergeDialogLayout->addLayout( layout48, 0, 0 ); languageChange(); resize( QSize(759, 380).expandedTo(minimumSizeHint()) ); // clearWState( WState_Polished ); // signals and slots connections connect( cancelBtn, SIGNAL( clicked() ), this, SLOT( reject() ) ); connect( okBtn, SIGNAL( clicked() ), this, SLOT( accept() ) ); connect( addBtn, SIGNAL( clicked() ), this, SLOT( addBtn_clicked() ) ); connect( removeBtn, SIGNAL( clicked() ), this, SLOT( removeBtn_clicked() ) ); connect( upBtn, SIGNAL( clicked() ), this, SLOT( upBtn_clicked() ) ); connect( downBtn, SIGNAL( clicked() ), this, SLOT( downBtn_clicked() ) ); connect( openBtn, SIGNAL( clicked() ), this, SLOT( openBtn_clicked() ) ); connect( fileNameBtn, SIGNAL( clicked() ), this, SLOT( fileNameBtn_clicked() ) ); #ifdef QT3 connect( mergeList, SIGNAL( currentChanged(QListBoxItem*) ), this, SLOT( mergeList_currentChanged(QListBoxItem*) ) ); connect( fileList, SIGNAL( currentChanged(QListBoxItem*) ), this, SLOT( fileList_currentChanged(QListBoxItem*) ) ); #else connect( mergeList, SIGNAL( currentChanged(Q3ListBoxItem*) ), this, SLOT( mergeList_currentChanged(Q3ListBoxItem*) ) ); connect( fileList, SIGNAL( currentChanged(Q3ListBoxItem*) ), this, SLOT( fileList_currentChanged(Q3ListBoxItem*) ) ); #endif // tab order setTabOrder( fileNameInput, fileNameBtn ); setTabOrder( fileNameBtn, openBtn ); setTabOrder( openBtn, addBtn ); setTabOrder( addBtn, removeBtn ); setTabOrder( removeBtn, upBtn ); setTabOrder( upBtn, downBtn ); setTabOrder( downBtn, okBtn ); setTabOrder( okBtn, cancelBtn ); // buddies textLabel1->setBuddy( fileNameInput ); } /* * Destroys the object and frees any allocated resources */ MergeDialog::~MergeDialog() { // no need to delete child widgets, Qt does it all for us } /* * Sets the strings of the subwidgets using the current * language. */ void MergeDialog::languageChange() { setCaption(tr("Insert pages from another document")); textLabel1->setText(tr("&Filename")); fileNameBtn->setText("..."); openBtn->setText(QObject::tr("&Open")); openBtn->setAccel(QKeySequence("Alt+O")); addBtn->setText("<<"); removeBtn->setText(">>"); upBtn->setText(QObject::tr("&Up")); upBtn->setAccel(QKeySequence("Alt+U")); downBtn->setText(QObject::tr("&Down")); downBtn->setAccel(QKeySequence("Alt+D")); cancelBtn->setText(QObject::tr("&Cancel")); cancelBtn->setAccel(QKeySequence("Alt+C")); okBtn->setText(QObject::tr("&Ok")); okBtn->setAccel(QKeySequence("Alt+O")); } } //namespace gui