inline bool KNMusicTagM4a::getBox(QDataStream &musicDataStream, KNMusicTagM4a::M4ABox &box, bool ignoreContent) { //Clear the box data. clearBox(box); //Set the box properties to independet box. box.independence=true; //Get the size of the box, reduce the 8 bytes size of itself and the name. musicDataStream>>box.size; box.size-=8; //Generate the name field. char nameField[5]={0}; //Get the name of the box. if(musicDataStream.readRawData(nameField, 4)==-1) { //If you cannot read the data, then it's failed to read the box. return false; } //Save the box name. box.name=nameField; //Get the content, or else we will simply get back. if(ignoreContent) { box.independence=false; //Skip the box size data. return musicDataStream.skipRawData(box.size); } //Allocate memory to store the box data. box.data=new char[box.size]; //Read the new data. return musicDataStream.readRawData(box.data, box.size); }
QWidget *MosaicAreaTool::getToolBarWidget() { m_latLineEdit = new QLineEdit(); m_latLineEdit->setValidator(new QDoubleValidator(-90.0, 90.0, 99, this)); m_lonLineEdit = new QLineEdit(); m_lonLineEdit->setValidator(new QDoubleValidator(this)); m_areaLineEdit = new QLineEdit(); m_areaLineEdit->setValidator(new QDoubleValidator(this)); m_areaLineEdit->setText("10000"); QLabel *latLabel = new QLabel("Latitude"); QLabel *lonLabel = new QLabel("Longitude"); QLabel *areaLabel = new QLabel("Size (meters)"); areaLabel->setToolTip("This is the width and the height of the box"); // Create the action buttons QPushButton *okButton = new QPushButton("Update Box"); connect(okButton, SIGNAL(clicked()), this, SLOT(userChangedBox())); QPushButton *clearButton = new QPushButton("Clear Box"); connect(clearButton, SIGNAL(clicked()), this, SLOT(clearBox())); // Put the buttons in a horizontal orientation QHBoxLayout *actionLayout = new QHBoxLayout(); actionLayout->addWidget(latLabel); actionLayout->addWidget(m_latLineEdit); actionLayout->addWidget(lonLabel); actionLayout->addWidget(m_lonLineEdit); actionLayout->addWidget(areaLabel); actionLayout->addWidget(m_areaLineEdit); actionLayout->addWidget(okButton); actionLayout->addWidget(clearButton); actionLayout->addStretch(1); actionLayout->setMargin(0); QWidget *toolBarWidget = new QWidget; toolBarWidget->setLayout(actionLayout); return toolBarWidget; }
void MosaicAreaTool::mouseButtonRelease(QPointF mouseLoc, Qt::MouseButton s) { if(!isActive()) return; if(s == Qt::LeftButton) { TProjection *tproj = (TProjection *) getWidget()->getProjection(); if(tproj && getWidget()->getView()->sceneRect().contains(mouseLoc)) { if(tproj->SetCoordinate(mouseLoc.x(), -1 * mouseLoc.y())) { if(m_drawBox != NULL) { clearBox(); } m_latLineEdit->setText(QString::number(tproj->Latitude(), 'g', 10)); m_lonLineEdit->setText(QString::number(tproj->Longitude(), 'g', 10)); userChangedBox(); } } } }
void MainWindow::on_dropSpreadAbilites_pressed() { clearBox(ui->comboBoxStrength); clearBox(ui->comboBoxDexterity); clearBox(ui->comboBoxConstitution); clearBox(ui->comboBoxIntelligence); clearBox(ui->comboBoxWisdom); clearBox(ui->comboBoxCharisma); listOfCandidatsToBecomeAbility = trueListOfCandidatsToBecomeAbility; setupComboBoxes(ui->comboBoxStrength, &listOfCandidatsToBecomeAbility); setupComboBoxes(ui->comboBoxDexterity, &listOfCandidatsToBecomeAbility); setupComboBoxes(ui->comboBoxConstitution, &listOfCandidatsToBecomeAbility); setupComboBoxes(ui->comboBoxIntelligence, &listOfCandidatsToBecomeAbility); setupComboBoxes(ui->comboBoxWisdom, &listOfCandidatsToBecomeAbility); setupComboBoxes(ui->comboBoxCharisma, &listOfCandidatsToBecomeAbility); }
void MosaicAreaTool::userChangedBox() { bool latValid = false; bool lonValid = false; bool areaValid = false; if(!m_latLineEdit || !m_lonLineEdit || !m_areaLineEdit) { clearBox(); return; } QString latitude = m_latLineEdit->text(); if(latitude != "Null" && latitude != "") { int cursorPos = 0; QValidator::State validLat = m_latLineEdit->validator()->validate(latitude, cursorPos); if(validLat != QValidator::Acceptable) { QMessageBox::warning(getWidget(), "Error", "Latitude value must be in the range -90 to 90", QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); } else { latValid = true; } } //Validate longitude value QString longitude = m_lonLineEdit->text(); if(longitude != "Null" && longitude != "" && latValid) { int cursorPos = 0; QValidator::State validLon = m_lonLineEdit->validator()->validate(longitude, cursorPos); if(validLon != QValidator::Acceptable) { QMessageBox::warning(getWidget(), "Error", "Longitude value invalid", QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); } else { lonValid = true; } } QString areaString = m_areaLineEdit->text(); if(areaString != "Null" && areaString != "" && latValid && lonValid) { int cursorPos = 0; QValidator::State validArea = m_areaLineEdit->validator()->validate(areaString, cursorPos); if(validArea != QValidator::Acceptable) { QMessageBox::warning(getWidget(), "Error", "Area value invalid", QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); } else { areaValid = true; } } if(latValid && lonValid && areaValid) { double lat = IString(latitude.toStdString()).ToDouble(); double lon = IString(longitude.toStdString()).ToDouble(); double area = IString(areaString.toStdString()).ToDouble(); Projection *projection = getWidget()->getProjection(); Projection::ProjectionType ptype = projection->projectionType(); if (projection && ptype == Projection::Triaxial) { TProjection * tproj = (TProjection *) projection; if (tproj->SetGround(lat, lon)) { QPointF scenePos(projection->XCoord(), -1 * projection->YCoord()); QRectF sceneRect(getWidget()->getView()->sceneRect()); if(sceneRect.contains(scenePos)) { if(m_box != NULL) { clearBox(); } Distance distance(area, Distance::Meters); QPolygonF boxPoly; QRectF latLonRange = calcLatLonRange(QPointF(lon, lat), distance); double xStep = latLonRange.width() / 100.0; double yStep = latLonRange.height() / 100.0; bool hasPole = (latLonRange.top() == -90 || latLonRange.bottom() == 90); double yPos = latLonRange.top(); if (yPos != -90) { for(double xPos = latLonRange.left(); xPos <= latLonRange.right(); xPos += xStep) { if (tproj->SetGround(yPos, xPos)) { QPointF pos(tproj->XCoord(), -1 * tproj->YCoord()); boxPoly << pos; } } } double xPos = latLonRange.right(); for (double yPos = latLonRange.top(); !hasPole && yPos <= latLonRange.bottom(); yPos += yStep) { if (tproj->SetGround(yPos, xPos)) { QPointF pos(tproj->XCoord(), -1 * tproj->YCoord()); boxPoly << pos; } } yPos = latLonRange.bottom(); if (yPos != 90) { for (double xPos = latLonRange.right(); xPos >= latLonRange.left(); xPos -= xStep) { if (tproj->SetGround(yPos, xPos)) { QPointF pos(tproj->XCoord(), -1 * tproj->YCoord()); boxPoly << pos; } } } xPos = latLonRange.left(); for (double yPos = latLonRange.bottom(); !hasPole && yPos >= latLonRange.top(); yPos -= yStep) { if (tproj->SetGround(yPos, xPos)) { QPointF pos(tproj->XCoord(), -1 * tproj->YCoord()); boxPoly << pos; } } if (boxPoly.size() > 0) { boxPoly << boxPoly[0]; m_box = new QGraphicsPolygonItem(boxPoly); m_box->setZValue(DBL_MAX); getWidget()->getScene()->addItem(m_box); getWidget()->getView()->centerOn(scenePos); } } else { QString message = "Lat/Lon not within this view."; QMessageBox::information(getWidget(), "Cannot Calculate Box", message, QMessageBox::Ok); } } } } }
bool KNMusicTagM4a::parseTag(QFile &musicFile, QDataStream &musicDataStream, KNMusicAnalysisItem &analysisItem) { Q_UNUSED(musicFile) //Some comments is from: // http://atomicparsley.sourceforge.net/mpeg-4files.html //The m4a file is made of a number of atoms, now they are called 'boxes'. // A box always begins with 4 bytes length and follows 4 bytes name. //And first we need to check the header box of the file. Its name is 'ftyp' //Check out the data. M4ABox ftypBox; if(!getBox(musicDataStream, ftypBox, true) || ftypBox.name!="ftyp") { //This cannot be a m4a file. return false; } //Metadata to be used with iTunes comes in the ilst box inside the moov box. //The structure of the ilst is: /* moov <- * |-udta * | |-meta * | | |-ilst */ //We have to keep reading until we find out the moov box. M4ABox moovBox; while(moovBox.name!="moov") { //If we cannot find a box, means there's no "moov" box, return false. if(!getBox(musicDataStream, moovBox)) { return true; } } //When we comes to here, we should find the "moov" box, expand the box to //find out the "udta" box. /* moov * |-udta <- * | |-meta * | | |-ilst */ QList<M4ABox> expandList; extractBox(moovBox, expandList); //Check the expand list. if(expandList.isEmpty()) { return true; } //Generate a empty box for "udta" box. M4ABox udtaBox; //Find all the box of the expand list of the "moov" box. for(auto i : expandList) { //Check the name of each box. if(i.name=="udta") { //Save the udta box. udtaBox=i; //Make the udta box to independent box. independent(udtaBox); //Clear the moov box. clearBox(moovBox); break; } } //Check out the data. if(udtaBox.name.isEmpty()) { //If the name of the udta box is still empty, means there's no udta box //in the moov box, then we are faild to parse. return true; } //Expand the "udta" box, and find "meta" box. /* moov * |-udta * | |-meta <- * | | |-ilst */ expandList.clear(); extractBox(udtaBox, expandList); //Check the expand list. if(expandList.isEmpty()) { return true; } //Generate a empty box for "meta" box. M4ABox metaBox; //Find all the box of the expand list of the "meta" box. for(auto i : expandList) { //Check the name of each box. if(i.name=="meta") { //Save the udta box. metaBox=i; //Make the meta box to independent box. independent(metaBox); //Clear the udta box. clearBox(udtaBox); break; } } //Check out the box. if(metaBox.name.isEmpty()) { //If the name of the meta box is still empty, means we cannot find meta //box in the meta box, then we are finished to parse. return true; } //Okay, now we can parse the meta box. /* moov * |-udta * | |-meta * | | |-ilst <- */ //Generate a box for ilst. M4ABox ilstBox; //Extract the meta box. if(!findIlstBox(metaBox, ilstBox)) { //Finished to parse the tag if we cannot file the ilst box. return true; } //Clear the meta box to recover the memory. clearBox(metaBox); //Okay we are now find out the ilst box. Extract the ilst box and we can now //fill our data to the detail info. expandList.clear(); extractBox(ilstBox, expandList); //Check out the expand list. if(expandList.isEmpty()) { //If there's no data inside the expand list, then our mission is //finished. return true; } //Write the expand list to the detail info. //Get the detail info. KNMusicDetailInfo &detailInfo=analysisItem.detailInfo; //Check all box inside the list. for(auto i : expandList) { //Check the name of the box. //If it's "covr", means we find out the album art box. if(i.name=="covr") { analysisItem.imageData["M4A"].append(QByteArray(i.data, i.size)); //Continue to next box. continue; } //Check the index of the box inside the map. int atomIndex=m_atomIndexMap.value(i.name, -1); //If the atom index is -1, then we have to continue to the next box. if(atomIndex==-1) { continue; } //Check the data size. if(i.size<16) { continue; } //Get the data position. //Actually there's another box inside the box of the i. //We can just skip it to read the data. char *dataPosition=i.data+16; int dataSize=i.size-16; //Output box data to detail info. switch(atomIndex) { case TrackNumber: //Ensure the data is enough to set the track number and track count. if(dataSize>6) { //Pick up the third byte data of the position as the track //number. detailInfo.textLists[TrackNumber]= QString::number(dataPosition[3]); //Pick up the fifth byte data of the position as the track //count. detailInfo.textLists[TrackCount]= QString::number(dataPosition[5]); } break; case DiscNumber: //Ensure the data is enough to set the disc number and disc count. if(dataSize>6) { //Pick up the third byte data of the position as the disc //number. detailInfo.textLists[DiscNumber]= QString::number(dataPosition[3]); //Pick up the fifth byte data of the position as the disc //count. detailInfo.textLists[DiscCount]= QString::number(dataPosition[5]); } break; case Rating: if(dataSize>0) { //Turn the first byte into the rating data. detailInfo.textLists[Rating]= QString::number((quint8)dataPosition[0]); } break; default: //Check out the data size first. if(dataSize>0) { //Set the whole data as the text data. setTextData(detailInfo.textLists[atomIndex], QByteArray(dataPosition, dataSize)); } break; } } return true; }
bool KNMusicTagM4a::writeTag(const KNMusicAnalysisItem &analysisItem) { //Get the detail info. const KNMusicDetailInfo &detailInfo=analysisItem.detailInfo; //Prepare and get the music file. QFile musicFile(detailInfo.filePath); //Open the file as read only mode. if(!musicFile.open(QIODevice::ReadOnly)) { //Failed to open the source. return false; } //Generate a temporary file, write the new data to the temporary file. QTemporaryFile updatedTagFile; //Open the temporary file, if we cannot open the temporary file it will be //failed to write the tag. if(!updatedTagFile.open()) { //Close the opened music file. musicFile.close(); return false; } //Generate a data stream for music file. QDataStream musicDataStream(&musicFile); //Read and copy the fytp box. If the first box isn't fytp box, then ignore //the file. M4ABox ftypBox; if(!getBox(musicDataStream, ftypBox) || ftypBox.name!="ftyp") { //Close both file. musicFile.close(); updatedTagFile.close(); //Failed to find a m4a file, return false. return false; } //Write ftyp data to the temporary file. writeBox(ftypBox, updatedTagFile); //We have to keep reading until we find out the moov box. //Output all the other data to updated tag file. M4ABox moovBox; for(;;) { //If we can get a new box. if(getBox(musicDataStream, moovBox)) { //Check out the name. if(moovBox.name=="moov") { break; } else { //Copy the data. writeBox(moovBox, updatedTagFile); } } else { //If we cannot find a box, means there's no "moov" box, failed to //write data. //Close both file. musicFile.close(); updatedTagFile.close(); //Failed to find a m4a file, return false. return false; } } //When we comes to here, we should find the "moov" box, expand the box to //find out the "udta" box. QList<M4ABox> moovExpandList; extractBox(moovBox, moovExpandList); //Generate a empty box for "udta" box. M4ABox udtaBox; //Check the expand list. if(moovExpandList.isEmpty() || !findBox("udta", udtaBox, moovExpandList)) { //If the name of the udta box is still empty, means there's no udta box //in the moov box, then we are faild to parse. //Close both file. musicFile.close(); updatedTagFile.close(); //Failed to find a m4a file, return false. return false; } //Expand the "udta" box, and find "meta" box. QList<M4ABox> udtaExpandList; extractBox(udtaBox, udtaExpandList); //Generate a empty box for "meta" box. M4ABox metaBox; //Check the expand list and find box. if(udtaExpandList.isEmpty() || !findBox("meta", metaBox, udtaExpandList)) { //If the name of the meta box is still empty, means we cannot find meta //box in the meta box, then we are finished to parse. //Close both file. musicFile.close(); updatedTagFile.close(); //Failed to find a m4a file, return false. return false; } //Okay, now we can parse the meta box. //Generate a box for ilst. M4ABox ilstBox; QList<M4ABox> metaExpandList; //Extract the meta box. extractMetaBox(metaBox, metaExpandList); //Find all box of the expand list. if(metaExpandList.isEmpty() || !findBox("ilst", ilstBox, metaExpandList)) { //We cannot find ilst box in the meta box. //Close both file. musicFile.close(); updatedTagFile.close(); //Failed to find a m4a file, return false. return false; } //Prepare the ilst expand list. QList<M4ABox> ilstExpandList; //Expand the ilst box. extractBox(ilstBox, ilstExpandList); //Now we have to write data to ilst expand list. for(int i=0; i<MusicDataCount; ++i) { //Get the atom name of current data. QString atomName=m_indexAtomMap.value(i, QString()); //Check if the atom name is empty, then go to the next. if(atomName.isEmpty()) { continue; } //Remove the exist data inside the ilst expand list. for(int j=ilstExpandList.size()-1; j>-1; --j) { //Check the name of the item. if(ilstExpandList.at(j).name==atomName) { //Remove it. ilstExpandList.removeAt(j); } } //Generate the raw data. QByteArray rawData; //Write the data to raw data. switch(i) { case TrackNumber: //Append three 0x00 first. rawData.append((char)0x00); rawData.append((char)0x00); rawData.append((char)0x00); //Append the track index. rawData.append((char)detailInfo.textLists[TrackNumber].toString() .toInt()); //Append splitter 0x00. rawData.append((char)0x00); //Append the track count. rawData.append((char)detailInfo.textLists[TrackCount].toString() .toInt()); //Append two 0x00 after. rawData.append((char)0x00); rawData.append((char)0x00); break; case DiscNumber: //Append three 0x00 first. rawData.append((char)0x00); rawData.append((char)0x00); rawData.append((char)0x00); //Append the disc index. rawData.append((char)detailInfo.textLists[DiscNumber].toString() .toInt()); //Append splitter 0x00. rawData.append((char)0x00); //Append the disc count. rawData.append((char)detailInfo.textLists[DiscCount].toString() .toInt()); //Append two 0x00 after. rawData.append((char)0x00); rawData.append((char)0x00); break; case Rating: //Append the rating to bytes. rawData.append((char)detailInfo.textLists[Rating].toString() .toInt()); break; default: //Translate the text data to UTF-8, without BOM. rawData=detailInfo.textLists[i].toString().toUtf8(); } //Generate the box. ilstExpandList.append(generateItemBox(i, atomName, rawData)); } //Remove all the album art atom. for(int j=ilstExpandList.size()-1; j>-1; --j) { //Check the name of the item. if(ilstExpandList.at(j).name=="covr") { //Remove it. ilstExpandList.removeAt(j); } } //Check album art. if(!analysisItem.coverImage.isNull()) { //Generate the raw data for the image. //Add the png raw data to image data. QByteArray imageData; QBuffer imageBuffer(&imageData); //Open the image buffer. imageBuffer.open(QIODevice::WriteOnly); //Save the data to image data. analysisItem.coverImage.save(&imageBuffer, "PNG"); //Close the image buffer. imageBuffer.close(); //Check the image data, if the data is not empty, then insert data. if(imageData.isEmpty()) { //Generate the flag data. char covrFlag[5]; covrFlag[0]=0x00; covrFlag[1]=0x00; covrFlag[2]=0x00; covrFlag[3]=14; //Generate item box, insert to list. ilstExpandList.append(generateItemBox(covrFlag, "covr", imageData)); } } //Combine the ilst data together. M4ABox updatedIlstBox=zipBox("ilst", ilstExpandList); //Clear the list and original ilst box. ilstExpandList.clear(); clearBox(ilstBox); //Replace the original ilst box. for(int i=metaExpandList.size()-1; i>-1; --i) { //Check the name. if(metaExpandList.at(i).name=="ilst") { //Replace the item. metaExpandList.replace(i, updatedIlstBox); //Stop searching. break; } } //Combine the meta expand list data. QByteArray metaRawData=combineBoxList(metaExpandList); //Clear up the meta expand list. metaExpandList.clear(); //Append the first four bytes raw data to the meta box raw data. metaRawData.prepend(metaBox.data, 4); //Clear up the no use meta box. clearBox(metaBox); clearBox(updatedIlstBox); //Set the data to new meta box. metaBox.name="meta"; metaBox.independence=true; metaBox.size=metaRawData.size(); metaBox.data=new char[metaBox.size]; memcpy(metaBox.data, metaRawData.data(), metaBox.size); //Replace the original meta box. for(int i=udtaExpandList.size()-1; i>-1; --i) { //Check the name. if(udtaExpandList.at(i).name=="meta") { //Replace the item. udtaExpandList.replace(i, metaBox); //Stop Searching. break; } } //Combine the udta data together. M4ABox updatedUdtaBox=zipBox("udta", udtaExpandList); //Clear the list and original udta box. udtaExpandList.clear(); clearBox(udtaBox); //Replace the original udta box. for(int i=moovExpandList.size()-1; i>-1; --i) { //Check the name. if(moovExpandList.at(i).name=="udta") { //Replace the item moovExpandList.replace(i, updatedUdtaBox); //Stop searching. break; } } //Combine the moov data together. M4ABox updatedMoovBox=zipBox("moov", moovExpandList); //Clear the list and original moov box. moovExpandList.clear(); clearBox(moovBox); //Write the new moov box to the updated tag file. writeBox(updatedMoovBox, updatedTagFile); //Clear up the updated moov box. clearBox(updatedMoovBox); //Copy the left data to the updated tag file. //Generate the music data cache. char *turboCache=new char[DataCacheSize]; //Copy the music data from the original music file, copy the //MusicDataCacheSize bytes once, until there's no bytes to copy. int bytesRead=musicFile.read(turboCache, DataCacheSize); while(bytesRead>0) { //Write the cache to temporary file. updatedTagFile.write(turboCache, bytesRead); //Read new data from the original file to cache. bytesRead=musicFile.read(turboCache, DataCacheSize); } //Close the music file. musicFile.close(); //Reset the temporary file. updatedTagFile.reset(); //Reopen the music file as write only mode, write all the udpated tag file //data to the music file. if(!musicFile.open(QIODevice::WriteOnly)) { //Close the updated tag file. updatedTagFile.close(); //Failed to write data. return false; } //Copy data from temporary file to music file. bytesRead=updatedTagFile.read(turboCache, DataCacheSize); while(bytesRead>0) { //Write the cache to music file. musicFile.write(turboCache, bytesRead); //Read new data from cache to the original file. bytesRead=updatedTagFile.read(turboCache, DataCacheSize); } //Close the music file and temporary file. musicFile.close(); updatedTagFile.close(); //Clear up the turbo memory. delete[] turboCache; //The tag rewrite is finished. return true; }